admin
2023-06-06 964a4e638feee3e541f008f56c15d5c5d3627547
看盘端html文件融入/华鑫接口接入
11个文件已修改
8个文件已添加
10806 ■■■■■ 已修改文件
gui_wx.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
huaxin/_traderapi.cp37-win32.pyd 补丁 | 查看 | 原始文档 | blame | 历史
huaxin/_traderapi.cp37-win_amd64.pyd 补丁 | 查看 | 原始文档 | blame | 历史
huaxin/_traderapi.cpython-37m-x86_64-linux-gnu.so 补丁 | 查看 | 原始文档 | blame | 历史
huaxin/test.py 623 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
huaxin/trade_server.py 641 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
huaxin/traderapi.py 8063 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
kp_html/kp/codes_list.html 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
kp_html/kp/css/banshuping.css 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
kp_html/kp/css/index23-05-04.css 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
kp_html/kp/index23-05-04.html 557 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
kp_html/kp/js/code_list.js 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
kp_html/kp/js/http.js 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
kp_html/kp/js/page.js 109 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
kp_html/kp/test.html 171 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main.py 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
res/setting.conf 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test.png 补丁 | 查看 | 原始文档 | blame | 历史
ths_util.py 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gui_wx.py
@@ -4,6 +4,7 @@
import time
import cv2
import win32con
import win32gui
import ocr_util
@@ -1297,7 +1298,6 @@
                continue
            rect = win32gui.GetWindowRect(hwnd)
            win32_util.visual_click(hwnd, (160, (rect[3] - rect[1]) // 2))
            # win32_util.visual_keyboard_F5(hwnd)
            time_space = setting.get_ths_auto_refresh_time_space()
            if time_space is None:
                time_space = 500
@@ -1379,5 +1379,8 @@
    app.MainLoop()
if __name__ == "__main__":
    pass
    ths_auto_refresh()
huaxin/_traderapi.cp37-win32.pyd
Binary files differ
huaxin/_traderapi.cp37-win_amd64.pyd
Binary files differ
huaxin/_traderapi.cpython-37m-x86_64-linux-gnu.so
Binary files differ
huaxin/test.py
New file
@@ -0,0 +1,623 @@
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import hashlib
import json
import random
import socket
import time
from huaxin import traderapi
# ---------------------------------------专业版-------------------------
# 登录用户
UserID = '00043201'
# 登陆密码
Password = '45249973'
# 投资者账户
InvestorID = '11160150'
# 经济公司部门代码
DepartmentID = '0003'
# 资金账户
AccountID = '00043201'
# 沪市股东账号
SSE_ShareHolderID = 'A00043201'
# 深市股东账号
SZSE_ShareHolderID = '700043201'
# # 登录用户
# UserID = '00572083'
# # 登陆密码
# Password = '16121950'
# # 投资者账户
# InvestorID = '11160150'
# # 经济公司部门代码
# DepartmentID = '0057'
# # 资金账户
# AccountID = '00572083'
# # 沪市股东账号
# SSE_ShareHolderID = 'A00572083'
# # 深市股东账号
# SZSE_ShareHolderID = '700572083'
class TraderSpi(traderapi.CTORATstpTraderSpi):
    def __init__(self, api):
        traderapi.CTORATstpTraderSpi.__init__(self)
        self.__api = api
        self.__req_id = 0
        self.__front_id = 0
        self.__session_id = 0
    def OnFrontConnected(self) -> "void":
        print('OnFrontConnected')
        # 获取终端信息
        self.__req_id += 1
        ret = self.__api.ReqGetConnectionInfo(self.__req_id)
        if ret != 0:
            print('ReqGetConnectionInfo fail, ret[%d]' % ret)
    def OnFrontDisconnected(self, nReason: "int") -> "void":
        print('OnFrontDisconnected: [%d]' % nReason)
    def OnRspGetConnectionInfo(self, pConnectionInfoField: "CTORATstpConnectionInfoField",
                               pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('inner_ip_address[%s]' % pConnectionInfoField.InnerIPAddress)
            print('inner_port[%d]' % pConnectionInfoField.InnerPort)
            print('outer_ip_address[%s]' % pConnectionInfoField.OuterIPAddress)
            print('outer_port[%d]' % pConnectionInfoField.OuterPort)
            print('mac_address[%s]' % pConnectionInfoField.MacAddress)
            # 请求登录
            login_req = traderapi.CTORATstpReqUserLoginField()
            # 支持以用户代码、资金账号和股东账号方式登录
            # (1)以用户代码方式登录
            login_req.LogInAccount = UserID
            login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_UserID
            # (2)以资金账号方式登录
            # login_req.DepartmentID = DepartmentID
            # login_req.LogInAccount = AccountID
            # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_AccountID
            # (3)以上海股东账号方式登录
            # login_req.LogInAccount = SSE_ShareHolderID
            # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SHAStock
            # (4)以深圳股东账号方式登录
            # login_req.LogInAccount = SZSE_ShareHolderID
            # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SZAStock
            # 支持以密码和指纹(移动设备)方式认证
            # (1)密码认证
            # 密码认证时AuthMode可不填
            # login_req.AuthMode = traderapi.TORA_TSTP_AM_Password
            login_req.Password = Password
            # (2)指纹认证
            # 非密码认证时AuthMode必填
            # login_req.AuthMode = traderapi.TORA_TSTP_AM_FingerPrint
            # login_req.DeviceID = '03873902'
            # login_req.CertSerial = '9FAC09383D3920CAEFF039'
            # 终端信息采集
            # UserProductInfo填写终端名称
            login_req.UserProductInfo = 'pyapidemo'
            # 按照监管要求填写终端信息
            login_req.TerminalInfo = 'PC;IIP=000.000.000.000;IPORT=00000;LIP=x.xx.xxx.xxx;MAC=123ABC456DEF;HD=XXXXXXXXXX'
            # 以下内外网IP地址若不填则柜台系统自动采集,若填写则以终端填值为准报送
            # login_req.MacAddress = '5C-87-9C-96-F3-E3'
            # login_req.InnerIPAddress = '10.0.1.102'
            # login_req.OuterIPAddress = '58.246.43.50'
            self.__req_id += 1
            ret = self.__api.ReqUserLogin(login_req, self.__req_id)
            if ret != 0:
                print('ReqUserLogin fail, ret[%d]' % ret)
        else:
            print('GetConnectionInfo fail, [%d] [%d] [%s]!!!' % (
                nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspUserLogin(self, pRspUserLoginField: "traderapi.CTORATstpRspUserLoginField",
                       pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('Login success! [%d]' % nRequestID)
            self.__front_id = pRspUserLoginField.FrontID
            self.__session_id = pRspUserLoginField.SessionID
            if 0:
                # 修改密码
                req_field = traderapi.CTORATstpUserPasswordUpdateField()
                req_field.UserID = UserID
                req_field.OldPassword = Password
                req_field.NewPassword = '123456'
                self.__req_id += 1
                ret = self.__api.ReqUserPasswordUpdate(req_field, self.__req_id)
                if ret != 0:
                    print('ReqUserPasswordUpdate fail, ret[%d]' % ret)
                return
            if 0:
                # 查询合约
                req_field = traderapi.CTORATstpQrySecurityField()
                # 以下字段不填表示不设过滤条件,即查询全部合约
                # req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE
                # req_field.SecurityID = '600000'
                self.__req_id += 1
                ret = self.__api.ReqQrySecurity(req_field, self.__req_id)
                if ret != 0:
                    print('ReqQrySecurity fail, ret[%d]' % ret)
            if 1:
                # 查询投资者
                req_field = traderapi.CTORATstpQryInvestorField()
                # 以下字段不填表示不设过滤条件
                # req_field.InvestorID = InvestorID
                self.__req_id += 1
                ret = self.__api.ReqQryInvestor(req_field, self.__req_id)
                if ret != 0:
                    print('ReqQryInvestor fail, ret[%d]' % ret)
            if 1:
                # 查询股东账号
                req_field = traderapi.CTORATstpQryShareholderAccountField()
                # 以下字段不填表示不设过滤条件,即查询所有股东账号
                # req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE
                self.__req_id += 1
                ret = self.__api.ReqQryShareholderAccount(req_field, self.__req_id)
                if ret != 0:
                    print('ReqQryShareholderAccount fail, ret[%d]' % ret)
            if 1:
                # 查询资金账号
                req_field = traderapi.CTORATstpQryTradingAccountField()
                # 以下字段不填表示不设过滤条件,即查询所有资金账号
                req_field.InvestorID = InvestorID
                req_field.DepartmentID = DepartmentID
                req_field.AccountID = AccountID
                self.__req_id += 1
                ret = self.__api.ReqQryTradingAccount(req_field, self.__req_id)
                if ret != 0:
                    print('ReqQryTradingAccount fail, ret[%d]' % ret)
            if 0:
                # 查询报单
                req_field = traderapi.CTORATstpQryOrderField()
                # 以下字段不填表示不设过滤条件,即查询所有报单
                # req_field.SecurityID = '600000'
                # req_field.InsertTimeStart = '09:35:00'
                # req_field.InsertTimeEnd = '10:00:00'
                # IsCancel字段填1表示只查询可撤报单
                req_field.IsCancel = 1
                self.__req_id += 1
                ret = self.__api.ReqQryOrder(req_field, self.__req_id)
                if ret != 0:
                    print('ReqQryOrder fail, ret[%d]' % ret)
            if 1:
                # 查询持仓
                req_field = traderapi.CTORATstpQryPositionField()
                # 以下字段不填表示不设过滤条件,即查询所有持仓
                # req_field.SecurityID = '600000'
                self.__req_id += 1
                ret = self.__api.ReqQryPosition(req_field, self.__req_id)
                if ret != 0:
                    print('ReqQryPosition fail, ret[%d]' % ret)
            if 1:
                req_field = traderapi.CTORATstpQryTradeField()
                self.__req_id += 1
                ret = api.ReqQryTrade(req_field, self.__req_id)
                if ret != 0:
                    raise Exception('ReqQryTrade fail, ret[%d]' % ret)
            if 1:
                # 请求报单
                req_field = traderapi.CTORATstpInputOrderField()
                req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE
                req_field.ShareholderID = SSE_ShareHolderID
                req_field.SecurityID = '603099'
                req_field.Direction = traderapi.TORA_TSTP_D_Sell
                req_field.VolumeTotalOriginal = 100
                '''
                上交所支持限价指令和最优五档剩撤、最优五档剩转限两种市价指令,对于科创板额外支持本方最优和对手方最优两种市价指令和盘后固定价格申报指令
                深交所支持限价指令和立即成交剩余撤销、全额成交或撤销、本方最优、对手方最优和最优五档剩撤五种市价指令
                限价指令和上交所科创板盘后固定价格申报指令需填写报单价格,其它市价指令无需填写报单价格
                以下以上交所限价指令为例,其它指令参考开发指南相关说明填写OrderPriceType、TimeCondition和VolumeCondition三个字段:
                '''
                req_field.LimitPrice = 11.74
                req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_LimitPrice
                req_field.TimeCondition = traderapi.TORA_TSTP_TC_GFD
                req_field.VolumeCondition = traderapi.TORA_TSTP_VC_AV
                '''
                OrderRef为报单引用,类型为整型,该字段报单时为选填
                若不填写,则系统会为每笔报单自动分配一个报单引用
                若填写,则需保证同一个TCP会话下报单引用严格单调递增,不要求连续递增,至少需从1开始编号
                '''
                # req_field.OrderRef = 1
                '''
                InvestorID为选填,若填写则需保证填写正确
                Operway为委托方式,根据券商要求填写,无特殊说明置空即可
                终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在报单回报和查询报单时返回给终端
                '''
                # req_field.SInfo = 'sinfo'
                # req_field.IInfo = 123
                '''
                其它字段置空
                '''
                self.__req_id += 1
                ret = self.__api.ReqOrderInsert(req_field, self.__req_id)
                if ret != 0:
                    print('ReqOrderInsert fail, ret[%d]' % ret)
            if 0:
                # 请求撤单
                req_field = traderapi.CTORATstpInputOrderActionField()
                req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE
                req_field.ActionFlag = traderapi.TORA_TSTP_AF_Delete
                # 撤单支持以下两种方式定位原始报单:
                # (1)报单引用方式
                # req_field.FrontID = self.__front_id
                # req_field.SessionID = self.__session_id
                # req_field.OrderRef = 1
                # (2)系统报单编号方式
                req_field.OrderSysID = '110019400000005'
                # OrderActionRef报单操作引用,用法同报单引用,可根据需要选填
                '''
                终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在查询撤单时返回给终端
                '''
                # req_field.SInfo = 'sinfo'
                # req_field.IInfo = 123
                '''
                委托方式字段根据券商要求填写,无特殊说明置空即可
                其它字段置空
                '''
                self.__req_id += 1
                ret = self.__api.ReqOrderAction(req_field, self.__req_id)
                if ret != 0:
                    print('ReqOrderAction fail, ret[%d]' % ret)
            if 1:
                # 查询集中交易资金
                req_field = traderapi.CTORATstpReqInquiryJZFundField()
                req_field.DepartmentID = DepartmentID
                req_field.AccountID = AccountID
                req_field.CurrencyID = traderapi.TORA_TSTP_CID_CNY
                self.__req_id += 1
                ret = self.__api.ReqInquiryJZFund(req_field, self.__req_id)
                if ret != 0:
                    print('ReqInquiryJZFund fail, ret[%d]' % ret)
            if 0:
                # 资金转移(包括资金调拨和银证转账)
                req_field = traderapi.CTORATstpInputTransferFundField()
                req_field.DepartmentID = DepartmentID
                req_field.AccountID = AccountID
                req_field.CurrencyID = traderapi.TORA_TSTP_CID_CNY
                req_field.Amount = 100000.0
                '''
                转移方向:
                TORA_TSTP_TRNSD_MoveIn表示资金从集中交易柜台调拨至快速交易柜台
                TORA_TSTP_TRNSD_MoveOut表示资金从快速交易柜台调拨至集中交易柜台
                TORA_TSTP_TRNSD_StockToBank表示证券快速交易系统资金转入银行,即出金
                TORA_TSTP_TRNSD_BankToStock表示银行资金转入证券快速交易系统,即入金
                以下说明各场景下字段填值:
                '''
                # (1)资金从集中交易柜台调拨至快速交易柜台
                req_field.TransferDirection = traderapi.TORA_TSTP_TRNSD_MoveIn
                # (2)资金从快速交易柜台调拨至集中交易柜台
                # req_field.TransferDirection = traderapi.TORA_TSTP_TRNSD_MoveOut
                # (3)证券快速交易系统资金转入银行,需填写银行代码和资金密码
                # req_field.TransferDirection = traderapi.TORA_TSTP_TRNSD_StockToBank
                # req_field.BankID = traderapi.TORA_TSTP_BKID_CCB
                # req_field.AccountPassword = '123456'
                # (4)银行资金转入证券快速交易系统,需填写银行代码和银行卡密码
                # req_field.TransferDirection = traderapi.TORA_TSTP_TRNSD_BankToStock
                # req_field.BankID = traderapi.TORA_TSTP_BKID_CCB
                # req_field.BankPassword = '123456'
                '''
                申请流水号ApplySerial字段为选填字段
                若不填写则柜台系统会自动生成一个申请流水号
                若填写则需保证同一个TCP会话下申请流水号不重复
                '''
                # req_field.ApplySerial = 1
                self.__req_id += 1
                ret = self.__api.ReqTransferFund(req_field, self.__req_id)
                if ret != 0:
                    print('ReqTransferFund fail, ret[%d]', ret)
            if 0:
                '''登出,目前登出成功连接会立即被柜台系统断开,终端不会收到OnRspUserLogout应答
                连接断开后接口内部会触发重新连接,为不使连接成功后又触发重新登录,需终端做好逻辑控制
                一般情况下若希望登出,直接调用Release接口即可,释放成功连接将被终端强制关闭,Release接口调用注意事项见下文说明
                '''
                req_field = traderapi.CTORATstpUserLogoutField()
                self.__req_id += 1
                ret = self.__api.ReqUserLogout(req_field, self.__req_id)
                if ret != 0:
                    print('ReqUserLogout fail, ret[%d]' % ret)
        else:
            print('Login fail!!! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
        return
    def OnRspUserPasswordUpdate(self, pUserPasswordUpdateField: "CTORATstpUserPasswordUpdateField",
                                pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspUserPasswordUpdate: OK! [%d]' % nRequestID)
        else:
            print('OnRspUserPasswordUpdate: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspOrderInsert(self, pInputOrderField: "CTORATstpInputOrderField", pRspInfoField: "CTORATstpRspInfoField",
                         nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspOrderInsert: OK! [%d] [%s]' % (nRequestID, pInputOrderField.SInfo))
        else:
            print('OnRspOrderInsert: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspOrderAction(self, pInputOrderActionField: "CTORATstpInputOrderActionField",
                         pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspOrderAction: OK! [%d]' % nRequestID)
        else:
            print('OnRspOrderAction: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspInquiryJZFund(self, pRspInquiryJZFundField: "CTORATstpRspInquiryJZFundField",
                           pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspInquiryJZFund: OK! [%d] [%.2f] [%.2f]'
                  % (nRequestID, pRspInquiryJZFundField.UsefulMoney, pRspInquiryJZFundField.FetchLimit))
        else:
            print('OnRspInquiryJZFund: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspTransferFund(self, pInputTransferFundField: "CTORATstpInputTransferFundField",
                          pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspTransferFund: OK! [%d]' % nRequestID)
        else:
            print('OnRspTransferFund: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRtnOrder(self, pOrderField: "CTORATstpOrderField") -> "void":
        print(
            '[%d]  OnRtnOrder: InvestorID[%s] SecurityID[%s] OrderRef[%d] OrderLocalID[%s] LimitPrice[%.2f] VolumeTotalOriginal[%d] OrderSysID[%s] OrderStatus[%s] StatusMsg[%s]'
            % (round(time.time() * 1000), pOrderField.InvestorID, pOrderField.SecurityID, pOrderField.OrderRef,
               pOrderField.OrderLocalID,
               pOrderField.LimitPrice, pOrderField.VolumeTotalOriginal, pOrderField.OrderSysID,
               pOrderField.OrderStatus,pOrderField.StatusMsg))
    def OnRtnTrade(self, pTradeField: "CTORATstpTradeField") -> "void":
        print(
            'OnRtnTrade: TradeID[%s] InvestorID[%s] SecurityID[%s] OrderRef[%d] OrderLocalID[%s] Price[%.2f] Volume[%d]'
            % (pTradeField.TradeID, pTradeField.InvestorID, pTradeField.SecurityID,
               pTradeField.OrderRef, pTradeField.OrderLocalID, pTradeField.Price, pTradeField.Volume))
    def OnRtnMarketStatus(self, pMarketStatusField: "CTORATstpMarketStatusField") -> "void":
        print('OnRtnMarketStatus: MarketID[%s] MarketStatus[%s]'
              % (pMarketStatusField.MarketID, pMarketStatusField.MarketStatus))
    def OnRspQrySecurity(self, pSecurityField: "CTORATstpSecurityField", pRspInfoField: "CTORATstpRspInfoField",
                         nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print(
                'OnRspQrySecurity[%d]: SecurityID[%s] SecurityName[%s] MarketID[%s] OrderUnit[%s] OpenDate[%s] UpperLimitPrice[%.2f] LowerLimitPrice[%.2f]'
                % (nRequestID, pSecurityField.SecurityID, pSecurityField.SecurityName, pSecurityField.MarketID,
                   pSecurityField.OrderUnit, pSecurityField.OpenDate, pSecurityField.UpperLimitPrice,
                   pSecurityField.LowerLimitPrice))
        else:
            print('查询合约结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryInvestor(self, pInvestorField: "CTORATstpInvestorField", pRspInfoField: "CTORATstpRspInfoField",
                         nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print('OnRspQryInvestor[%d]: InvestorID[%s]  Operways[%s]'
                  % (nRequestID, pInvestorField.InvestorID,
                     pInvestorField.Operways))
        else:
            print('查询投资者结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryShareholderAccount(self, pShareholderAccountField: "CTORATstpShareholderAccountField",
                                   pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int",
                                   bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print('OnRspQryShareholderAccount[%d]: InvestorID[%s] ExchangeID[%s] ShareholderID[%s]'
                  % (nRequestID, pShareholderAccountField.InvestorID, pShareholderAccountField.ExchangeID,
                     pShareholderAccountField.ShareholderID))
        else:
            print('查询股东账户结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryTradingAccount(self, pTradingAccountField: "CTORATstpTradingAccountField",
                               pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print(
                'OnRspQryTradingAccount[%d]: DepartmentID[%s] InvestorID[%s] AccountID[%s] CurrencyID[%s] UsefulMoney[%.2f] FetchLimit[%.2f]'
                % (nRequestID, pTradingAccountField.DepartmentID, pTradingAccountField.InvestorID,
                   pTradingAccountField.AccountID, pTradingAccountField.CurrencyID,
                   pTradingAccountField.UsefulMoney, pTradingAccountField.FetchLimit))
        else:
            print('查询资金账号结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryOrder(self, pOrderField: "CTORATstpOrderField", pRspInfoField: "CTORATstpRspInfoField",
                      nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print(
                'OnRspQryOrder[%d]: SecurityID[%s] OrderLocalID[%s] OrderRef[%d] OrderSysID[%s] VolumeTraded[%d] OrderStatus[%s] OrderSubmitStatus[%s], StatusMsg[%s]'
                % (nRequestID, pOrderField.SecurityID, pOrderField.OrderLocalID, pOrderField.OrderRef,
                   pOrderField.OrderSysID,
                   pOrderField.VolumeTraded, pOrderField.OrderStatus, pOrderField.OrderSubmitStatus,
                   pOrderField.StatusMsg))
        else:
            print('查询报单结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryPosition(self, pPositionField: "CTORATstpPositionField", pRspInfoField: "CTORATstpRspInfoField",
                         nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print('OnRspQryPosition[%d]: InvestorID[%s] SecurityID[%s] HistoryPos[%d] TodayBSPos[%d] TodayPRPos[%d]'
                  % (nRequestID, pPositionField.InvestorID, pPositionField.SecurityID, pPositionField.HistoryPos,
                     pPositionField.TodayBSPos, pPositionField.TodayPRPos))
        else:
            print('查询持仓结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
        # 查询成交响应,参数pTradeField是一个CTORATstpTradeField类对象
    def OnRspQryTrade(self, pTradeField: "CTORATstpTradeField", pRspInfoField: "CTORATstpRspInfoField",
                      nRequestID: "int", bIsLast: "bool") -> "void":
        print("查询成交响应")
        if not bIsLast:
            print(pTradeField.OrderSysID)
        else:
            pass
def __send_msg(data):
    # 签名
    list_str = []
    for k in data:
        list_str.append(f"{k}={data[k]}")
    list_str.sort()
    __str = "&".join(list_str)+"JiaBei@!*."
    md5 = hashlib.md5(__str.encode(encoding='utf-8')).hexdigest()
    data["sign"] = md5
    # 生成socket,连接server
    ip_port = ("127.0.0.1", 9002)  # server地址和端口号(最好是10000以后)
    client = socket.socket()  # 生成socket,连接server
    client.connect(ip_port)
    client.send(json.dumps(data).encode("utf-8"))
    rec = client.recv(1024000)
    result = rec.decode("gbk")
    client.close()
    return result
def __buy():
    data = {"type": 0, "req_id": f"test-{random.randint(0, 10000)}",
            "data": json.dumps({"code": "601985", "count": 1000, "price": 6.85})}
    result = __send_msg(data)
    print("下单结果", json.loads(result))
def __cancel_buy():
    data = {"type": 1, "req_id": f"test-{random.randint(0, 10000)}",
            "data": json.dumps({"code": "601985", "order_sys_id": "110018100000015"})}
    result = __send_msg(data)
    print("取消订单", json.loads(result))
def __list_delegate():
    data = {"type": 2, "req_id": f"test-{random.randint(0, 10000)}"}
    result_str = __send_msg(data)
    result_json = json.loads(result_str)
    print("可撤委托列表", result_json)
    if result_json["code"] == 0:
        for item in result_json["data"]:
            print(item)
    else:
        print(result_json['msg'])
def __list_traded():
    data = {"type": 3, "req_id": f"test-{random.randint(0, 10000)}"}
    result = __send_msg(data)
    result = json.loads(result)
    print("已成交列表")
    for item in result["data"]:
        print(item)
if __name__ == '__main__':
    # __buy()
    __cancel_buy()
    __list_delegate()
    __list_traded()
    # if 1>0:
    #     return;
    # print("初始化交易服务器")
    # api = traderapi.CTORATstpTraderApi.CreateTstpTraderApi('./flow', False)
    # # 创建回调对象
    # spi = TraderSpi(api)
    # # 注册回调接口
    # api.RegisterSpi(spi)
    #
    # # 注册多个交易前置服务地址,用逗号隔开
    # # api.RegisterFront('tcp://10.0.1.101:6500,tcp://10.0.1.101:26500')
    # # 注册名字服务器地址,支持多服务地址逗号隔开
    # # api.RegisterNameServer('tcp://10.0.1.101:52370')
    # # api.RegisterNameServer('tcp://10.0.1.101:52370,tcp://10.0.1.101:62370')
    #
    # if 1:  # 模拟环境,TCP 直连Front方式
    #     # 注册单个交易前置服务地址
    #     # TD_TCP_FrontAddress = "tcp://210.14.72.21:4400"  # 仿真交易环境
    #     TD_TCP_FrontAddress = "tcp://210.14.72.15:4400"  # 24小时环境A套
    #     # TD_TCP_FrontAddress="tcp://210.14.72.16:9500" #24小时环境B套
    #     api.RegisterFront(TD_TCP_FrontAddress)
    #     # 注册多个交易前置服务地址,用逗号隔开 形如: api.RegisterFront("tcp://10.0.1.101:6500,tcp://10.0.1.101:26500")
    #     print("TD_TCP_FensAddress[sim or 24H]::%s\n" % TD_TCP_FrontAddress)
    #
    # else:  # 模拟环境,FENS名字服务器方式
    #     TD_TCP_FensAddress = "tcp://210.14.72.21:42370";  # 模拟环境通用fens地址
    #     '''********************************************************************************
    #         * 注册 fens 地址前还需注册 fens 用户信息,包括环境编号、节点编号、Fens 用户代码等信息
    #         * 使用名字服务器的好处是当券商系统部署方式发生调整时外围终端无需做任何前置地址修改
    #         * *****************************************************************************'''
    #     fens_user_info_field = traderapi.CTORATstpFensUserInfoField()
    #     fens_user_info_field.FensEnvID = "stock"  # 必填项,暂时固定为“stock”表示普通现货柜台
    #     fens_user_info_field.FensNodeID = "sim"  # 必填项,生产环境需按实际填写,仿真环境为sim
    #     fens_user_info_field.FensNodeID, = "24a"  # 必填项,生产环境需按实际填写,24小时A套环境为24a
    #     # fens_user_info_field.FensNodeID="24b" #必填项,生产环境需按实际填写,24小时B套环境为24b
    #     api.RegisterFensUserInfo(fens_user_info_field)
    #     api.RegisterNameServer(TD_TCP_FensAddress)
    #     # 注册名字服务器地址,支持多服务地址逗号隔开 形如:api.RegisterNameServer('tcp://10.0.1.101:52370,tcp://10.0.1.101:62370')
    #     print("TD_TCP_FensAddress[%s]::%s\n" % (fens_user_info_field.FensNodeID, TD_TCP_FensAddress))
    #
    # # 订阅私有流
    # api.SubscribePrivateTopic(traderapi.TORA_TERT_QUICK)
    # # 订阅公有流
    # api.SubscribePublicTopic(traderapi.TORA_TERT_QUICK)
    # # 启动接口
    # api.Init()
    # input()
huaxin/trade_server.py
New file
@@ -0,0 +1,641 @@
import hashlib
import json
import logging
import socket
import socketserver
import time
from huaxin import traderapi
UserID = '00043201'
# 登陆密码
Password = '45249973'
# 投资者账户
InvestorID = '11160150'
# 经济公司部门代码
DepartmentID = '0003'
# 资金账户
AccountID = '00043201'
# 沪市股东账号
SSE_ShareHolderID = 'A00043201'
# 深市股东账号
SZSE_ShareHolderID = '700043201'
# # 登录用户
# UserID = '00572083'
# # 登陆密码
# Password = '16121950'
# # 投资者账户
# InvestorID = '11160150'
# # 经济公司部门代码
# DepartmentID = '0057'
# # 资金账户
# AccountID = '00572083'
# # 沪市股东账号
# SSE_ShareHolderID = 'A00572083'
# # 深市股东账号
# SZSE_ShareHolderID = '700572083'
TYPE_BUY = 0
TYPE_CANCEL_BUY = 1
TYPE_LIST_DELEGATE = 2
TYPE_LIST_TRADED = 3
class TradeSimpleApi:
    req_id = 0
    __buy_sinfo_set = set()
    __cancel_buy_sinfo_set = set()
    # sinfo char(32)
    def buy(self, code, count, price, sinfo):
        if sinfo in self.__buy_sinfo_set:
            raise Exception(f'下单请求已经提交:{sinfo}')
        self.__buy_sinfo_set.add(sinfo)
        self.req_id += 1
        # 请求报单
        req_field = traderapi.CTORATstpInputOrderField()
        # TORA_TSTP_EXD_COMM(0): 通用(内部使用)
        # TORA_TSTP_EXD_SSE(1): 上海交易所
        # TORA_TSTP_EXD_SZSE(2): 深圳交易所
        # TORA_TSTP_EXD_HK(3): 香港交易所
        # TORA_TSTP_EXD_BSE(4): 北京证券交易所
        if code.find('00') == 0:
            req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SZSE
            req_field.ShareholderID = SZSE_ShareHolderID
        elif code.find('60') == 0:
            req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE
            req_field.ShareholderID = SSE_ShareHolderID
        # 证券代码
        req_field.SecurityID = code
        req_field.Direction = traderapi.TORA_TSTP_D_Buy
        req_field.VolumeTotalOriginal = count
        req_field.SInfo = sinfo
        '''
        上交所支持限价指令和最优五档剩撤、最优五档剩转限两种市价指令,对于科创板额外支持本方最优和对手方最优两种市价指令和盘后固定价格申报指令
        深交所支持限价指令和立即成交剩余撤销、全额成交或撤销、本方最优、对手方最优和最优五档剩撤五种市价指令
        限价指令和上交所科创板盘后固定价格申报指令需填写报单价格,其它市价指令无需填写报单价格
        以下以上交所限价指令为例,其它指令参考开发指南相关说明填写OrderPriceType、TimeCondition和VolumeCondition三个字段:
        '''
        req_field.LimitPrice = price
        req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_LimitPrice
        req_field.TimeCondition = traderapi.TORA_TSTP_TC_GFD
        req_field.VolumeCondition = traderapi.TORA_TSTP_VC_AV
        print(req_field)
        '''
        OrderRef为报单引用,类型为整型,该字段报单时为选填
        若不填写,则系统会为每笔报单自动分配一个报单引用
        若填写,则需保证同一个TCP会话下报单引用严格单调递增,不要求连续递增,至少需从1开始编号
        '''
        # req_field.OrderRef = 1
        '''
        InvestorID为选填,若填写则需保证填写正确
        Operway为委托方式,根据券商要求填写,无特殊说明置空即可
        终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在报单回报和查询报单时返回给终端
        '''
        # req_field.SInfo = 'sinfo'
        # req_field.IInfo = 123
        '''
        其它字段置空
        '''
        ret = api.ReqOrderInsert(req_field, self.req_id)
        if ret != 0:
            raise Exception('ReqOrderInsert fail, ret[%d]' % ret)
        return
    def cancel_buy(self, code, order_sys_id, sinfo):
        if sinfo in self.__cancel_buy_sinfo_set:
            raise Exception(f'撤单请求已经提交:{sinfo}')
        self.__cancel_buy_sinfo_set.add(sinfo)
        self.req_id += 1
        # 请求撤单
        req_field = traderapi.CTORATstpInputOrderActionField()
        if code.find('00') == 0:
            req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SZSE
        elif code.find('60') == 0:
            req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE
        req_field.ActionFlag = traderapi.TORA_TSTP_AF_Delete
        # 撤单支持以下两种方式定位原始报单:
        # (1)报单引用方式
        # req_field.FrontID = self.__front_id
        # req_field.SessionID = self.__session_id
        # req_field.OrderRef = 1
        # (2)系统报单编号方式
        req_field.OrderSysID = order_sys_id
        # OrderActionRef报单操作引用,用法同报单引用,可根据需要选填
        '''
        终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在查询撤单时返回给终端
        '''
        req_field.SInfo = sinfo
        # req_field.IInfo = 123
        '''
        委托方式字段根据券商要求填写,无特殊说明置空即可
        其它字段置空
        '''
        ret = api.ReqOrderAction(req_field, self.req_id)
        if ret != 0:
            raise Exception('ReqOrderAction fail, ret[%d]' % ret)
        return
    # 查询当日可撤销的委托
    def list_delegate_orders(self):
        self.req_id += 1
        req_id = self.req_id
        req_field = traderapi.CTORATstpQryOrderField()
        # 以下字段不填表示不设过滤条件,即查询所有报单
        # req_field.SecurityID = '600000'
        # req_field.InsertTimeStart = '09:35:00'
        # req_field.InsertTimeEnd = '10:00:00'
        # IsCancel字段填1表示只查询可撤报单
        req_field.IsCancel = 1
        # req_field.SInfo = sinfo
        ret = api.ReqQryOrder(req_field, req_id)
        if ret != 0:
            raise Exception('ReqQryOrder fail, ret[%d]' % ret)
        return req_id
    # 查询当日成交的订单
    def list_traded_orders(self):
        self.req_id += 1
        req_id = self.req_id
        req_field = traderapi.CTORATstpQryTradeField()
        ret = api.ReqQryTrade(req_field, req_id)
        if ret != 0:
            raise Exception('ReqQryTrade fail, ret[%d]' % ret)
        return req_id
class TraderSpi(traderapi.CTORATstpTraderSpi):
    def __init__(self, api, callback):
        traderapi.CTORATstpTraderSpi.__init__(self)
        self.__api = api
        self.__front_id = 0
        self.__session_id = 0
        self.__data_callback = callback
        self.__temp_order_list_dict = {}
    def OnFrontConnected(self) -> "void":
        print('OnFrontConnected')
        # 获取终端信息
        TradeSimpleApi.req_id += 1
        ret = self.__api.ReqGetConnectionInfo(TradeSimpleApi.req_id)
        if ret != 0:
            print('ReqGetConnectionInfo fail, ret[%d]' % ret)
        print(ret)
    def OnFrontDisconnected(self, nReason: "int") -> "void":
        print('OnFrontDisconnected: [%d]' % nReason)
    def OnRspGetConnectionInfo(self, pConnectionInfoField: "CTORATstpConnectionInfoField",
                               pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('inner_ip_address[%s]' % pConnectionInfoField.InnerIPAddress)
            print('inner_port[%d]' % pConnectionInfoField.InnerPort)
            print('outer_ip_address[%s]' % pConnectionInfoField.OuterIPAddress)
            print('outer_port[%d]' % pConnectionInfoField.OuterPort)
            print('mac_address[%s]' % pConnectionInfoField.MacAddress)
            # 请求登录
            login_req = traderapi.CTORATstpReqUserLoginField()
            # 支持以用户代码、资金账号和股东账号方式登录
            # (1)以用户代码方式登录
            login_req.LogInAccount = UserID
            login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_UserID
            # (2)以资金账号方式登录
            # login_req.DepartmentID = DepartmentID
            # login_req.LogInAccount = AccountID
            # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_AccountID
            # (3)以上海股东账号方式登录
            # login_req.LogInAccount = SSE_ShareHolderID
            # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SHAStock
            # (4)以深圳股东账号方式登录
            # login_req.LogInAccount = SZSE_ShareHolderID
            # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SZAStock
            # 支持以密码和指纹(移动设备)方式认证
            # (1)密码认证
            # 密码认证时AuthMode可不填
            # login_req.AuthMode = traderapi.TORA_TSTP_AM_Password
            login_req.Password = Password
            # (2)指纹认证
            # 非密码认证时AuthMode必填
            # login_req.AuthMode = traderapi.TORA_TSTP_AM_FingerPrint
            # login_req.DeviceID = '03873902'
            # login_req.CertSerial = '9FAC09383D3920CAEFF039'
            # 终端信息采集
            # UserProductInfo填写终端名称
            login_req.UserProductInfo = 'jiabei'
            # 按照监管要求填写终端信息
            login_req.TerminalInfo = 'PC;IIP=123.112.154.118;IPORT=50361;LIP=192.168.118.107;MAC=54EE750B1713FCF8AE5CBD58;HD=TF655AY91GHRVL'
            # 以下内外网IP地址若不填则柜台系统自动采集,若填写则以终端填值为准报送
            # login_req.MacAddress = '5C-87-9C-96-F3-E3'
            # login_req.InnerIPAddress = '10.0.1.102'
            # login_req.OuterIPAddress = '58.246.43.50'
            TradeSimpleApi.req_id += 1
            ret = self.__api.ReqUserLogin(login_req, TradeSimpleApi.req_id)
            if ret != 0:
                print('ReqUserLogin fail, ret[%d]' % ret)
        else:
            print('GetConnectionInfo fail, [%d] [%d] [%s]!!!' % (
                nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspUserLogin(self, pRspUserLoginField: "CTORATstpRspUserLoginField", pRspInfoField: "CTORATstpRspInfoField",
                       nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('Login success! [%d]' % nRequestID)
            self.__front_id = pRspUserLoginField.FrontID
            self.__session_id = pRspUserLoginField.SessionID
            if 1:
                # 查询股东账号
                req_field = traderapi.CTORATstpQryShareholderAccountField()
                # 以下字段不填表示不设过滤条件,即查询所有股东账号
                # req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE
                TradeSimpleApi.req_id += 1
                ret = self.__api.ReqQryShareholderAccount(req_field, TradeSimpleApi.req_id)
                if ret != 0:
                    print('ReqQryShareholderAccount fail, ret[%d]' % ret)
        else:
            print('Login fail!!! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspUserPasswordUpdate(self, pUserPasswordUpdateField: "CTORATstpUserPasswordUpdateField",
                                pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspUserPasswordUpdate: OK! [%d]' % nRequestID)
        else:
            print('OnRspUserPasswordUpdate: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspOrderInsert(self, pInputOrderField: "CTORATstpInputOrderField", pRspInfoField: "CTORATstpRspInfoField",
                         nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('[%d] OnRspOrderInsert: OK! [%d]' % (round(time.time() * 1000), nRequestID))
        else:
            print('OnRspOrderInsert: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
            self.__data_callback(TYPE_BUY, nRequestID, {"sinfo": pInputOrderField.SInfo, "orderStatus": -1,
                                                        "orderStatusMsg": pRspInfoField.ErrorMsg})
    def OnRspOrderAction(self, pInputOrderActionField: "CTORATstpInputOrderActionField",
                         pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspOrderAction: OK! [%d]' % nRequestID)
            self.__data_callback(TYPE_CANCEL_BUY, nRequestID, {"sinfo": pInputOrderActionField.SInfo,
                                                               "orderSysID": pInputOrderActionField.OrderSysID,
                                                               "cancel": 1})
        else:
            print('OnRspOrderAction: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
            self.__data_callback(TYPE_CANCEL_BUY, nRequestID, {"sinfo": pInputOrderActionField.SInfo,
                                                               "orderSysID": pInputOrderActionField.OrderSysID,
                                                               "cancel": 0, "errorID": pRspInfoField.ErrorID,
                                                               "errorMsg": pRspInfoField.ErrorMsg})
    def OnRspInquiryJZFund(self, pRspInquiryJZFundField: "CTORATstpRspInquiryJZFundField",
                           pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspInquiryJZFund: OK! [%d] [%.2f] [%.2f]'
                  % (nRequestID, pRspInquiryJZFundField.UsefulMoney, pRspInquiryJZFundField.FetchLimit))
        else:
            print('OnRspInquiryJZFund: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspTransferFund(self, pInputTransferFundField: "CTORATstpInputTransferFundField",
                          pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void":
        if pRspInfoField.ErrorID == 0:
            print('OnRspTransferFund: OK! [%d]' % nRequestID)
        else:
            print('OnRspTransferFund: Error! [%d] [%d] [%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRtnOrder(self, pOrderField: "CTORATstpOrderField") -> "void":
        print(
            '[%d] OnRtnOrder: SInfo[%s] InvestorID[%s] SecurityID[%s] OrderRef[%d] OrderLocalID[%s] LimitPrice[%.2f] VolumeTotalOriginal[%d] OrderSysID[%s] OrderStatus[%s]'
            % (round(time.time() * 1000), pOrderField.SInfo, pOrderField.InvestorID, pOrderField.SecurityID,
               pOrderField.OrderRef, pOrderField.OrderLocalID,
               pOrderField.LimitPrice, pOrderField.VolumeTotalOriginal, pOrderField.OrderSysID,
               pOrderField.OrderStatus))
        if pOrderField.OrderStatus != traderapi.TORA_TSTP_OST_Unknown:
            self.__data_callback(TYPE_BUY, 0, {"sinfo": pOrderField.SInfo, "securityId": pOrderField.SecurityID,
                                               "orderLocalId": pOrderField.OrderLocalID,
                                               "orderStatus": pOrderField.OrderStatus,
                                               "statusMsg": pOrderField.StatusMsg,
                                               "orderSysID": pOrderField.OrderSysID,
                                               "accountId": pOrderField.AccountID})
    def OnRtnTrade(self, pTradeField: "CTORATstpTradeField") -> "void":
        print(
            'OnRtnTrade: TradeID[%s] InvestorID[%s] SecurityID[%s] OrderRef[%d] OrderLocalID[%s] Price[%.2f] Volume[%d]'
            % (pTradeField.TradeID, pTradeField.InvestorID, pTradeField.SecurityID,
               pTradeField.OrderRef, pTradeField.OrderLocalID, pTradeField.Price, pTradeField.Volume))
    def OnRtnMarketStatus(self, pMarketStatusField: "CTORATstpMarketStatusField") -> "void":
        print('OnRtnMarketStatus: MarketID[%s] MarketStatus[%s]'
              % (pMarketStatusField.MarketID, pMarketStatusField.MarketStatus))
    def OnRspQrySecurity(self, pSecurityField: "CTORATstpSecurityField", pRspInfoField: "CTORATstpRspInfoField",
                         nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print(
                'OnRspQrySecurity[%d]: SecurityID[%s] SecurityName[%s] MarketID[%s] OrderUnit[%s] OpenDate[%s] UpperLimitPrice[%.2f] LowerLimitPrice[%.2f]'
                % (nRequestID, pSecurityField.SecurityID, pSecurityField.SecurityName, pSecurityField.MarketID,
                   pSecurityField.OrderUnit, pSecurityField.OpenDate, pSecurityField.UpperLimitPrice,
                   pSecurityField.LowerLimitPrice))
        else:
            print('查询合约结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryInvestor(self, pInvestorField: "CTORATstpInvestorField", pRspInfoField: "CTORATstpRspInfoField",
                         nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print('OnRspQryInvestor[%d]: InvestorID[%s] InvestorName[%s] Operways[%s]'
                  % (nRequestID, pInvestorField.InvestorID, pInvestorField.InvestorName,
                     pInvestorField.Operways))
        else:
            print('查询投资者结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryShareholderAccount(self, pShareholderAccountField: "CTORATstpShareholderAccountField",
                                   pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int",
                                   bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print('OnRspQryShareholderAccount[%d]: InvestorID[%s] ExchangeID[%s] ShareholderID[%s]'
                  % (nRequestID, pShareholderAccountField.InvestorID, pShareholderAccountField.ExchangeID,
                     pShareholderAccountField.ShareholderID))
        else:
            print('查询股东账户结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryTradingAccount(self, pTradingAccountField: "CTORATstpTradingAccountField",
                               pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print(
                'OnRspQryTradingAccount[%d]: DepartmentID[%s] InvestorID[%s] AccountID[%s] CurrencyID[%s] UsefulMoney[%.2f] FetchLimit[%.2f]'
                % (nRequestID, pTradingAccountField.DepartmentID, pTradingAccountField.InvestorID,
                   pTradingAccountField.AccountID, pTradingAccountField.CurrencyID,
                   pTradingAccountField.UsefulMoney, pTradingAccountField.FetchLimit))
        else:
            print('查询资金账号结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    def OnRspQryOrder(self, pOrderField: "CTORATstpOrderField", pRspInfoField: "CTORATstpRspInfoField",
                      nRequestID: "int", bIsLast: "bool") -> "void":
        print('查询报单回调', bIsLast)
        if nRequestID not in self.__temp_order_list_dict:
            self.__temp_order_list_dict[nRequestID] = []
        if not bIsLast:
            print(
                'OnRspQryOrder[%d]: SecurityID[%s] OrderLocalID[%s] Direction[%s] OrderRef[%d] OrderSysID[%s] VolumeTraded[%d] OrderStatus[%s] OrderSubmitStatus[%s], StatusMsg[%s]'
                % (nRequestID, pOrderField.SecurityID, pOrderField.OrderLocalID, pOrderField.Direction,
                   pOrderField.OrderRef, pOrderField.OrderSysID,
                   pOrderField.VolumeTraded, pOrderField.OrderStatus, pOrderField.OrderSubmitStatus,
                   pOrderField.StatusMsg))
            self.__temp_order_list_dict[nRequestID].append(
                {"securityID": pOrderField.SecurityID, "orderLocalID": pOrderField.OrderLocalID,
                 "direction": pOrderField.Direction, "orderSysID": pOrderField.OrderSysID,
                 "insertTime": pOrderField.InsertTime, "insertDate": pOrderField.InsertDate,
                 "acceptTime": pOrderField.AcceptTime, "cancelTime": pOrderField.CancelTime,
                 "limitPrice": pOrderField.LimitPrice,
                 "turnover": pOrderField.Turnover,
                 "volume": pOrderField.VolumeTotalOriginal,
                 "volumeTraded": pOrderField.VolumeTraded, "orderStatus": pOrderField.OrderStatus,
                 "orderSubmitStatus": pOrderField.OrderSubmitStatus, "statusMsg": pOrderField.StatusMsg})
        else:
            print('查询报单结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
            self.__data_callback(TYPE_LIST_DELEGATE, nRequestID, self.__temp_order_list_dict[nRequestID])
            self.__temp_order_list_dict.pop(nRequestID)
    def OnRspQryPosition(self, pPositionField: "CTORATstpPositionField", pRspInfoField: "CTORATstpRspInfoField",
                         nRequestID: "int", bIsLast: "bool") -> "void":
        if bIsLast != 1:
            print('OnRspQryPosition[%d]: InvestorID[%s] SecurityID[%s] HistoryPos[%d] TodayBSPos[%d] TodayPRPos[%d]'
                  % (nRequestID, pPositionField.InvestorID, pPositionField.SecurityID, pPositionField.HistoryPos,
                     pPositionField.TodayBSPos, pPositionField.TodayPRPos))
        else:
            print('查询持仓结束[%d] ErrorID[%d] ErrorMsg[%s]'
                  % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg))
    # 成交回报,参数pTradeField是一个CTORATstpTradeField类对象
    def OnRtnTrade(self, pTradeField: "CTORATstpTradeField") -> "void":
        print("OnRtnTrade")
    # 查询成交响应,参数pTradeField是一个CTORATstpTradeField类对象
    def OnRspQryTrade(self, pTradeField: "CTORATstpTradeField", pRspInfoField: "CTORATstpRspInfoField",
                      nRequestID: "int", bIsLast: "bool") -> "void":
        print("查询成交响应")
        if nRequestID not in self.__temp_order_list_dict:
            self.__temp_order_list_dict[nRequestID] = []
        if not bIsLast:
            self.__temp_order_list_dict[nRequestID].append(
                {"tradeID": pTradeField.TradeID, "securityID": pTradeField.SecurityID,
                 "orderLocalID": pTradeField.OrderLocalID,
                 "direction": pTradeField.Direction, "orderSysID": pTradeField.OrderSysID, "price": pTradeField.Price,
                 "tradeTime": pTradeField.TradeTime,
                 "volume": pTradeField.Volume, "tradeDate": pTradeField.TradeDate, "tradingDay": pTradeField.TradingDay,
                 "PbuID": pTradeField.PbuID, "accountID": pTradeField.AccountID})
        else:
            self.__data_callback(TYPE_LIST_TRADED, nRequestID, self.__temp_order_list_dict[nRequestID])
            self.__temp_order_list_dict.pop(nRequestID)
class MyTCPServer(socketserver.TCPServer):
    def __init__(self, server_address, RequestHandlerClass):
        socketserver.TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate=True)
# 如果使用异步的形式则需要再重写ThreadingTCPServer
class MyThreadingTCPServer(socketserver.ThreadingMixIn, MyTCPServer): pass
class MyBaseRequestHandle(socketserver.BaseRequestHandler):
    __inited = False
    @classmethod
    def traderapi_callback(cls, type, req_id, data):
        print("回调", type, req_id, data)
        key = req_id
        if type == TYPE_BUY or type == TYPE_CANCEL_BUY:
            key = data["sinfo"]
        try:
            if cls.__req_socket_dict and key in cls.__req_socket_dict:
                cls.__req_socket_dict[key].send(json.dumps({"code": 0, "data": data}).encode('gbk'))
                cls.__req_socket_dict.pop(key)
        except Exception as e:
            logging.exception(e)
    def setup(self):
        print("----setup方法被执行-----", self.__inited)
        self.__init()
    @classmethod
    def __init(cls):
        if cls.__inited:
            return True
        cls.__inited = True
        cls.__req_socket_dict = {}
        cls.__tradeSimpleApi = TradeSimpleApi()
    def __is_sign_right(self, data_json):
        list_str = []
        sign = data_json["sign"]
        data_json.pop("sign")
        for k in data_json:
            list_str.append(f"{k}={data_json[k]}")
        list_str.sort()
        __str = "&".join(list_str) + "JiaBei@!*."
        md5 = hashlib.md5(__str.encode(encoding='utf-8')).hexdigest()
        if md5 != sign:
            raise Exception("签名出错")
    def handle(self):
        host = self.client_address[0]
        super().handle()
        sk: socket.socket = self.request
        while True:
            try:
                data = sk.recv(1024 * 100)
                data_str = str(data, encoding="utf-8")
                if not data_str:
                    continue
                print("接收到数据:", data_str)
                return_str = ''
                try:
                    data_json = json.loads(data_str)
                    self.__is_sign_right(data_json)
                    _type = data_json["type"]
                    _req_id = data_json["req_id"]
                    _data = data_json.get("data")
                    if _type == 0:
                        # 下单
                        _data = json.loads(_data)
                        code = _data["code"]
                        count = _data["count"]
                        price = round(float(_data["price"]), 2)
                        print("下单参数:", code, count, price)
                        self.__tradeSimpleApi.buy(code, count, price, _req_id)
                        # 下单成功
                        self.__req_socket_dict[_req_id] = sk
                        # 等待3s
                        time.sleep(2)
                    elif _type == 1:
                        # 撤单
                        _data = json.loads(_data)
                        code = _data["code"]
                        order_sys_id = _data["order_sys_id"]
                        print("撤单参数:", code, order_sys_id)
                        self.__tradeSimpleApi.cancel_buy(code, order_sys_id, _req_id)
                        # 撤单成功
                        self.__req_socket_dict[_req_id] = sk
                        time.sleep(2)
                    elif _type == 2:
                        # 委托列表
                        local_req_id = self.__tradeSimpleApi.list_delegate_orders()
                        self.__req_socket_dict[local_req_id] = sk
                        time.sleep(3)
                    elif _type == 3:
                        # 成交列表
                        local_req_id = self.__tradeSimpleApi.list_traded_orders()
                        self.__req_socket_dict[local_req_id] = sk
                        time.sleep(3)
                    elif _type == 100:
                        # 活动日志
                        pass
                    else:
                        sk.send(return_str.encode())
                    pass
                except Exception as e:
                    return_str = json.dumps({"code": 1, "msg": str(e)})
                    sk.send(return_str.encode())
            except:
                pass
    def finish(self):
        super().finish()
def __init_trade_data_server():
    print("初始化交易服务器")
    global api
    api = traderapi.CTORATstpTraderApi.CreateTstpTraderApi('./flow', False)
    # 创建回调对象
    global spi
    spi = TraderSpi(api, MyBaseRequestHandle.traderapi_callback)
    # 注册回调接口
    api.RegisterSpi(spi)
    # 注册多个交易前置服务地址,用逗号隔开
    # api.RegisterFront('tcp://10.0.1.101:6500,tcp://10.0.1.101:26500')
    # 注册名字服务器地址,支持多服务地址逗号隔开
    # api.RegisterNameServer('tcp://10.0.1.101:52370')
    # api.RegisterNameServer('tcp://10.0.1.101:52370,tcp://10.0.1.101:62370')
    if 1:  # 模拟环境,TCP 直连Front方式
        # 注册单个交易前置服务地址
        # TD_TCP_FrontAddress = "tcp://210.14.72.21:4400"  # 仿真交易环境
        TD_TCP_FrontAddress = "tcp://210.14.72.15:4400"  # 24小时环境A套
        # TD_TCP_FrontAddress="tcp://210.14.72.16:9500" #24小时环境B套
        api.RegisterFront(TD_TCP_FrontAddress)
        # 注册多个交易前置服务地址,用逗号隔开 形如: api.RegisterFront("tcp://10.0.1.101:6500,tcp://10.0.1.101:26500")
        print("TD_TCP_FensAddress[sim or 24H]::%s\n" % TD_TCP_FrontAddress)
    else:  # 模拟环境,FENS名字服务器方式
        TD_TCP_FensAddress = "tcp://210.14.72.21:42370";  # 模拟环境通用fens地址
        '''********************************************************************************
            * 注册 fens 地址前还需注册 fens 用户信息,包括环境编号、节点编号、Fens 用户代码等信息
            * 使用名字服务器的好处是当券商系统部署方式发生调整时外围终端无需做任何前置地址修改
            * *****************************************************************************'''
        fens_user_info_field = traderapi.CTORATstpFensUserInfoField()
        fens_user_info_field.FensEnvID = "stock"  # 必填项,暂时固定为“stock”表示普通现货柜台
        fens_user_info_field.FensNodeID = "sim"  # 必填项,生产环境需按实际填写,仿真环境为sim
        fens_user_info_field.FensNodeID, = "24a"  # 必填项,生产环境需按实际填写,24小时A套环境为24a
        # fens_user_info_field.FensNodeID="24b" #必填项,生产环境需按实际填写,24小时B套环境为24b
        api.RegisterFensUserInfo(fens_user_info_field)
        api.RegisterNameServer(TD_TCP_FensAddress)
        # 注册名字服务器地址,支持多服务地址逗号隔开 形如:api.RegisterNameServer('tcp://10.0.1.101:52370,tcp://10.0.1.101:62370')
        print("TD_TCP_FensAddress[%s]::%s\n" % (fens_user_info_field.FensNodeID, TD_TCP_FensAddress))
    # 订阅私有流
    api.SubscribePrivateTopic(traderapi.TORA_TERT_QUICK)
    # 订阅公有流
    api.SubscribePublicTopic(traderapi.TORA_TERT_QUICK)
    # 启动接口
    api.Init()
def run():
    __init_trade_data_server()
    laddr = "", 9002
    tcpserver = MyThreadingTCPServer(laddr, MyBaseRequestHandle)  # 注意:参数是MyBaseRequestHandle
    # tcpserver.handle_request()  # 只接受一个客户端连接
    tcpserver.serve_forever()
if __name__ == "__main__":
    run()
huaxin/traderapi.py
New file
Diff too large
kp_html/kp/codes_list.html
New file
@@ -0,0 +1,237 @@
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>看盘端</title>
        <link rel="stylesheet" type="text/css" href="./css/banshuping.css" />
        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
        <script src="http://cdn.yeshitv.com/js/vue.min.js"></script>
        <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
        <script src="js/code_list.js"></script>
        <script src="js/kpl.js"></script>
        <style>
        </style>
    </head>
    <body>
        <div id="app">
            <div class="top">
                <span>
                    <h2 style="margin-left: 18px; font-size: 20px;">{{code_name}}
                    </h2>
                </span>
            </div>
            <div>
                <!-- 买前评分 -->
                <div>
                    <span>
                        <table class="half-width">
                            <caption class="table-name">主动买入</caption>
                        <tbody>
                            <tr>
                                <td style="padding: 0;border: none">
                                    <div class="code-table-container">
                                        <div v-for="(item,i) in initiative_buy_codes"
                                            :style="{'border-left-style': i%3==0?'solid':'none','border-top-style': i<3?'solid':'none'}">
                                            <span v-if="item.limit_up"><img src="./images/limit_up.png"></span>
                                            <span v-else-if="item.open_limit_up"><img
                                                    src="./images/stop_up.png"></span>
                                            <span v-else>
                                                <img src="./images/stop_up.png" style="visibility: hidden;">
                                            </span>
                                            <span class="num-style">{{item.name}}</span>
                                            <span class="num-style">{{item.code}}</span>
                                            <span class="score-card-color yellow">{{item.score}}</span>
                                        </div>
                                    </div>
                                </td>
                            </tr>
                        </tbody>
                        </table>
                    </span>
                    <span>
                        <table class="half-width">
                            <caption class="table-name">被动买入</caption>
                            <tbody>
                                <tr>
                                    <td style="padding: 0;border: none">
                                        <div class="code-table-container">
                                            <div v-for="(item,i) in passive_buy_codes"
                                                :style="{'border-left-style': i%3==0?'solid':'none','border-top-style': i<3?'solid':'none'}">
                                                <span v-if="item.limit_up"><img src="./images/limit_up.png"></span>
                                                <span v-else-if="item.open_limit_up"><img
                                                        src="./images/stop_up.png"></span>
                                                <span v-else>
                                                    <img src="./images/stop_up.png" style="visibility: hidden;">
                                                </span>
                                                <span class="num-style">{{item.name}}</span>
                                                <span class="num-style">{{item.code}}</span>
                                                <span class="score-card-color yellow">{{item.score}}</span>
                                            </div>
                                        </div>
                                    </td>
                                </tr>
                            </tbody>
                            <tfoot></tfoot>
                        </table>
                    </span>
                </div>
                <!-- H撤单 -->
                <table v-if="trade_data&&trade_data.h_cancel">
                    <caption class="table-name">H撤 <span v-if="trade_data.h_cancel.computed_info">(已撤{{trade_data.h_cancel.computed_info[1]}}/目标{{trade_data.h_cancel.computed_info[0]}})</span></caption>
                    <tbody>
                        <tr><td style="padding: 0;">
                        <div class="scroll-y" style="max-height: 350px;">
                            <table>
                                <thead>
                                    <tr><td>时间</td><td>手数</td><td>金额</td><td>是否撤单</td></tr>
                                </thead>
                                <tbody>
                                <tr v-for="(item,i) in trade_data.h_cancel.datas" >
                                    <td><span class="red"> {{item[0]}}</span></td>
                                    <td><span class="red"> {{item[1]}}</span></td>
                                    <td><span class="red"> {{item[2]}}</span></td>
                                    <td><span class="red" v-if="item[3]"> 已撤</span></td>
                                </tr>
                                </tbody>
                            </table>
                        </div>
                        </td></tr>
                    </tbody>
                </table>
                <!-- 交易参数 -->
                <table v-if="trade_data">
                    <caption class="table-name">交易参数</caption>
                    <tr>
                        <td>买入意愿</td>
                        <td>
                            <span class="bold yellow"
                                :class="{'yellow':trade_data.star.count>0}">{{trade_data.star.desc}}</span>
                            <img v-for="(item,i) in trade_data.star.count" src="./images/star.png" /
                                style="margin-left: 3px;"></span>
                        </td>
                    </tr>
                    <tr>
                        <td>是否可以买入</td>
                        <td v-if="trade_data.can_buy_info">
                            <span class="bold" v-if="trade_data.can_buy_info[0]">可以买入</span>
                            <span class="bold red" v-else>不可以买入:{{trade_data.can_buy_info[2]}}</span>
                        </td>
                        <td v-else>
                            <span class="bold" >未知</span>
                        </td>
                    </tr>
                    <tr>
                        <td>安全笔数</td>
                        <td>固定安全笔数<span class="num-style ">{{trade_data.safe_count.base}}</span>笔,衰减后安全笔数<span
                                class="num-style ">{{trade_data.safe_count.now}}</span>笔</td>
                    </tr>
                    <tr>
                        <td>动态M值</td>
                        <td>固定M值<span class="num-style ">{{trade_data.m_val.base}}万</span>&nbsp;&nbsp;&nbsp;动态M值<span
                                class="num-style ">{{trade_data.m_val.now}}万</span></td>
                    </tr>
                    <tr>
                        <td>买前大单</td>
                        <td>固定买前大单<span class="num-style ">{{trade_data.big_num.base}}</span>笔,衰减后买前大单<span
                                class="num-style ">{{trade_data.big_num.now}}</span>笔
                        </td>
                    </tr>
                    <tr>
                        <td>成交进度</td>
                        <td><span v-if="trade_data.trade_progress">
                                <span class="num-style ">{{trade_data.trade_progress.time}}</span>&nbsp;
                                <span class="num-style ">{{trade_data.trade_progress.num}}手</span>&nbsp;
                                <span class="num-style ">{{trade_data.trade_progress.money}}万</span>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>买入信号</td>
                        <td>
                            <span v-if="trade_data.buy_single">
                                <span class="num-style ">{{trade_data.buy_single.time}}</span>&nbsp;
                                <span class="num-style ">{{trade_data.buy_single.num}}手</span>&nbsp;
                                <span class="num-style ">{{trade_data.buy_single.money}}万</span>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>买入执行位</td>
                        <td>
                            <span v-if="trade_data.buy_exec">
                                <span class="num-style ">{{trade_data.buy_exec.time}}</span>&nbsp;
                                <span class="num-style ">{{trade_data.buy_exec.num}}手</span>&nbsp;
                                <span class="num-style ">{{trade_data.buy_exec.money}}万</span>
                            </span>
                            <span v-else class="num-style red bold">未下单</span>
                        </td>
                    </tr>
                </table>
                <!-- 今日挂撤记录 -->
                <table v-if="trade_record">
                    <caption class="table-name">今日挂撤记录</caption>
                    <thead>
                        <tr>
                            <td>是否炸板:<span v-if="trade_record.open_limit_up"> <span><img
                                            src="./images/stop_up.png">&nbsp;</span>炸板&nbsp;&nbsp;
                                    <span class="num-style ">{{trade_record.open_limit_up}}</span></span>
                                <span v-else class="num-style ">未炸板</span>
                            </td>
                        </tr>
                    </thead>
                    <tr>
                        <td>
                        <div style="width: 100%;display: flex;justify-content: space-between;flex-wrap: wrap;">
                            <div style="width: 50%;" v-for="(item,index) in trade_record.records">
                                <span v-if="item.type==1">第{{item.index}}次下单:<span class="num-style ">{{item.time}}</span> <span class="score-card-color yellow">{{item.score}}</span></span>
                                <span v-else> 撤单:<span class="num-style ">{{item.time}}</span> {{item.desc}} </span>
                            </div>
                        </div>
                        </td>
                    </tr>
                </table>
            </div>
        </div>
        <script>
        </script>
    </body>
</html>
kp_html/kp/css/banshuping.css
@@ -311,3 +311,30 @@
#kpl-feng_xiang tr td:nth-child(5){
    padding-right:0;
}
.code-table-container {
    word-wrap: break-word;
    display: flex;
    width: 520px;
    flex-wrap: wrap;
    color:white;
}
.code-table-container div {
    border-right-style: solid;
    border-bottom-style: solid;
    width: 167px;
    text-align: left;
    padding-left: 5px;
    border-color: white;
    border-width: 1px;
    color:white;
}
.scroll-y {
    overflow: hidden;
    overflow-y: auto;
    white-space: nowrap;
    outline: none;
}
kp_html/kp/css/index23-05-04.css
@@ -121,6 +121,15 @@
    /* border: 1px solid #191921; */
}
.score-data tr>td:nth-child(3){
    max-width: 400px;
}
.score-data tr>td:nth-child(1){
    width: 80px;
    min-width: 80px;
}
.half-width {
    float: left;
    width: 50%;
@@ -501,15 +510,36 @@
.market-container {
    width: 450px;
    height: 83px;
    vertical-align: center;
    width: 520px;
    height: 190px;
    word-wrap: break-word;
    display: flex;
    flex-wrap: wrap;
    box-sizing: border-box;
    overflow: hidden;
    overflow-y: auto;
    white-space: nowrap;
    outline: none;
}
.market-container .item {
    box-sizing: border-box;
    position: relative;
    width:100px;
    display: inline-block;
    padding-right: 20px;
    padding:5px 5px 0px 5px;
    border-right: solid 1px #EEE;
    border-bottom: solid 1px #EEE;
}
.market-container .item .delete{
    position: absolute;
    right:3px;
    bottom:3px;
}
.market-container .item .delete img{
    height:20px;
}
.market-container .item span {
@@ -519,7 +549,7 @@
.shoubanzuogundong tr {
    background: #FFF;
    height: 75px;
    height: 85px;
    cursor: pointer;
}
@@ -533,7 +563,7 @@
/* 板块 */
.budinggundong {
    height: 55px;
    height: 75px;
}
.budinggundong .scroll-x {
@@ -544,11 +574,20 @@
    display: inline-block;
    padding: 0 5px;
    border-right: solid 1px #EEE;
    vertical-align: top;
}
.budinggundong .scroll-x span {
    display: block;
}
.budinggundong .scroll-x span:nth-child(1){
    padding-bottom: 2px;
}
.budinggundong .scroll-x span:nth-child(2){
    padding-bottom: 2px;
}
.code-table-container {
    word-wrap: break-word;
@@ -569,6 +608,9 @@
.want_code_content{
    padding: 10px;
    flex-wrap: wrap;
    width: 200px;
    display: flex;
}
.want_code_content .item{
kp_html/kp/index23-05-04.html
@@ -3,13 +3,14 @@
    <head>
        <meta charset="utf-8">
        <title>看盘端</title>
        <link rel="stylesheet" type="text/css" href="./css/index23-05-04.css" />
        <link rel="stylesheet" type="text/css" href="./css/index23-05-04.css?_=1" />
        <link rel="stylesheet" type="text/css" href="layui/css/layui.css" />
        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
        <script src="http://cdn.yeshitv.com/js/vue.min.js"></script>
        <script src="js/qwebchannel.js"></script>
        <script src="js/http.js"></script>
        <script src="layui/layui.js"></script>
        <script src="js/kpl.js"></script>
        <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
        <style>
@@ -21,9 +22,11 @@
            <div class="top">
                <span>
                    <h2 class="bold-content" style="margin-left: 18px; font-size: 20px;">{{code_name}}<span><a class="button-blue"
                                style="margin-top: -34px;margin-left: 280px;" href="#" :class="{'btn-invalid':!trade_data.order}"  @click="cancel_order">已撤单</a></span><span><a
                                class="button-blue" style="margin-top: -28px;margin-left: 920px;" href="#" @click="refresh">刷新</a></span>
                    <h2 class="bold-content" style="margin-left: 18px; font-size: 20px;">{{code_name}}<span><a
                                class="button-blue" style="margin-top: -34px;margin-left: 280px;" href="#"
                                :class="{'btn-invalid':!trade_data.order}" @click="cancel_order">已撤单</a></span><span><a
                                class="button-blue" style="margin-top: -28px;margin-left: 920px;" href="#"
                                @click="refresh">刷新</a></span>
                    </h2>
                </span>
@@ -35,7 +38,7 @@
                    <!-- 买前评分 -->
                    <div style="width: 536px;">
                        <table v-if="score_data">
                        <table v-if="score_data" class="score-data">
                            <caption class="table-name">买前评分</caption>
                            <tbody class="maiqian">
                                <tr>
@@ -44,10 +47,10 @@
                                        <div class="num-style">{{score_data.volume.score}}</div>
                                    </td>
                                    <td style="margin: 0 auto;"><span class="bold-content">前量:</span>
                                        <span class="num-style">{{score_data.volume.high.num}}万手</span>&nbsp;&nbsp;<span class="bold-content">实量:</span><span
                                        <span class="num-style">{{score_data.volume.high.num}}万手</span>&nbsp;&nbsp;<span
                                            class="bold-content">实量:</span><span
                                            class="num-style">{{score_data.volume.now}}万手</span>&nbsp;&nbsp;&nbsp;
                                            <span
                                            class="bold-content">量比:</span><span
                                        <span class="bold-content">量比:</span><span
                                            class="red">【{{score_data.volume.rate}}%】</span>
                                    </td>
                                </tr>
@@ -162,18 +165,31 @@
                                    <td><span class="bold">今天</span></td>
                                    <td>
                                        <span v-if="kpl_code_info.today">
                                        <span class="red">【{{kpl_code_info.today[0]}}】</span>|&nbsp;<span class="num-style">{{kpl_code_info.today[2]}}</span>
                                    </span>
                                            <span class="red">【{{kpl_code_info.today[0][0]}}】</span><span v-if="kpl_code_info.today[0][1]">({{kpl_code_info.today[0][1]}})</span>&nbsp;|&nbsp;
                                            <span v-for="(item,index) in kpl_code_info.today[2]">
                                                <span class="num-style">{{item[0]}}</span><span v-if="item[1]">({{item[1]}})</span><span v-if="index!=kpl_code_info.today[2].length-1">、</span>
                                            </span>
                                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                                        </span>
                                        <br>
                                        二级:
                                        <span class="num-style" v-if="kpl_code_info.industry">
                                            {{kpl_code_info.industry[0]}}
                                            <span v-if="kpl_code_info.industry[1]">({{kpl_code_info.industry[1]}})</span>
                                        </span>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="min-width: 35px;"><span class="bold">历史</span></td>
                                    <td>
                                        <span v-for="(item,i) in kpl_code_info.code_records">
                                            <span class="num-style red">【{{item[0]}}】</span>|&nbsp;<span class="num-style">{{item[2]}}</span>
                                            <span
                                                class="num-style">({{item[1]}})</span>
                                            &nbsp;&nbsp;&nbsp;&nbsp;
                                            <span class="num-style red">【{{item[0][0]}}】</span> <span v-if="item[0][1]">({{item[0][1]}})</span>|&nbsp;
                                            <span v-for="(item1,i1) in item[2]">
                                                <span class="num-style">{{item1[0]}}</span><span v-if="item1[1]">({{item1[1]}})</span> <span v-if="i1!=item[2].length-1">、</span>
                                            </span>
                                            <br>
                                        </span>
                                    </td>
@@ -184,9 +200,10 @@
                                    <td><span class="bold">板块</span></td>
                                    <td class="budinggundong">
                                        <div class="scroll-x">
                                            <div v-for="(item,i) in kpl_code_info.plate">
                                            <div v-for="(item,i) in kpl_code_info.plate" >
                                                <span class="num-style">{{item[1]}}</span>
                                                <span class="num-style">{{item[2]}}%</span>
                                                <span class="num-style">{{item[3]}}</span>
                                            </div>
                                        </div>
@@ -203,105 +220,83 @@
                <!-- 右侧板块 -->
                <div style=" float: right;">
                    <div>
                        <div>
                            <!-- 主动买入 -->
                            <table style="width: 520px;">
                                <caption class="table-name">主动买入</caption>
                                <thead>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td style="padding: 0;border: none">
                                            <div class="code-table-container">
                                                <div v-for="(item,i) in initiative_buy_codes"
                                                    :style="{'border-left-style': i%3==0?'solid':'none','border-top-style': i<3?'solid':'none'}">
                                                    <span v-if="item.limit_up"><img src="./images/limit_up.png"></span>
                                                    <span v-else-if="item.open_limit_up"><img
                                                            src="./images/stop_up.png"></span>
                                                    <span v-else>
                                                        <img src="./images/stop_up.png" style="visibility: hidden;">
                                                    </span>
                                                    <span class="num-style">{{item.name}}</span>
                                                    <span class="num-style">{{item.code}}</span>
                                                    <span class="score-card-color yellow">{{item.score}}</span>
                        <div style="height: 340px;">
                            <div>
                                <table style="width: 520px;">
                                    <caption class="table-name">
                                        <div class="child-title" :class="{'child-title-active':jingxuan_data_type==0}"
                                            @click="get_jingxuan_data(0)">精选流入</div>
                                        <div class="child-title" :class="{'child-title-active':jingxuan_data_type==1}"
                                            @click="get_jingxuan_data(1)">精选流出</div>
                                    </caption>
                                    <thead>
                                    </thead>
                                    <tbody>
                                        <tr style="padding:0px;">
                                            <td style="padding:0px;">
                                                <div class="market-container">
                                                    <div class="item" v-for="(item,index) in jingxuan_datas">
                                                        <span :class="{'green':item[4]==1}">{{item[1]}}</span>
                                                        <span
                                                            :class="{'green':item[4]==1}">{{money_desc(item[3])}}</span>
                                                        <span class='delete'
                                                            :style="{'visibility':item[4]==1?'hidden':'visible' }"><img
                                                                src="images/delete.png"
                                                                v-on:click="forbidden_plate(item[1],1)"></span>
                                                    </div>
                                                </div>
                                            </div>
                                        </td>
                                    </tr>
                                            </td>
                                        </tr>
                                </tbody>
                                <tfoot></tfoot>
                            </table>
                                    </tbody>
                                </table>
                                <table style="width: 520px;">
                                    <caption class="table-name">
                                        <div class="child-title" :class="{'child-title-active':industry_data_type==0}"
                                            @click="get_industry_data(0)">行业流入</div>
                                        <div class="child-title" :class="{'child-title-active':industry_data_type==1}"
                                            @click="get_industry_data(1)">行业流出</div>
                                    </caption>
                                    <thead>
                                    </thead>
                                    <tbody>
                                        <tr style="padding:0px;">
                                            <td style="padding:0px;">
                                                <div class="market-container">
                                                    <div class="item" v-for="(item,index) in industry_datas">
                                                        <span :class="{'green':item[4]==1}">{{item[1]}}</span>
                                                        <span
                                                            :class="{'green':item[4]==1}">{{money_desc(item[3])}}</span>
                                                        <span class='delete'
                                                            :style="{'visibility':item[4]==1?'hidden':'visible' }"><img
                                                                src="images/delete.png"
                                                                v-on:click="forbidden_plate(item[1],0)"></span>
                                                    </div>
                                                </div>
                                            </td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                        <div>
                            <!--  被动买入-->
                            <table style="width: 520px;">
                                <caption class="table-name">被动买入</caption>
                                <thead>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td style="padding: 0;border: none">
                                            <div class="code-table-container">
                                                <div v-for="(item,i) in passive_buy_codes"
                                                    :style="{'border-left-style': i%3==0?'solid':'none','border-top-style': i<3?'solid':'none'}">
                                                    <span v-if="item.limit_up"><img src="./images/limit_up.png"></span>
                                                    <span v-else-if="item.open_limit_up"><img
                                                            src="./images/stop_up.png"></span>
                                                    <span v-else>
                                                        <img src="./images/stop_up.png" style="visibility: hidden;">
                                                    </span>
                                                    <span class="num-style">{{item.name}}</span>
                                                    <span class="num-style">{{item.code}}</span>
                                                    <span class="score-card-color yellow">{{item.score}}</span>
                                                </div>
                                            </div>
                                        </td>
                                    </tr>
                                </tbody>
                                <tfoot></tfoot>
                            </table>
                        </div>
                        <div>
                            <!-- 行业涨幅 -->
                            <table style="width: 520px;" class="market">
                                <caption class="table-name">
                                    <div class="child-title" :class="{'child-title-active':industry_data_type==2}" @click="get_industry_data(2)"> 精选流入</div>
                                    <div class="child-title" :class="{'child-title-active':industry_data_type==3}" @click="get_industry_data(3)"> 精选流出</div>
                                    <div class="child-title" :class="{'child-title-active':industry_data_type==0}" @click="get_industry_data(0)">行业流入</div>
                                    <div class="child-title" :class="{'child-title-active':industry_data_type==1}" @click="get_industry_data(1)"> 行业流出</div>
                                </caption>
                                <thead>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td class="market-name">
                                            <span class="bold">板块</span>
                                            <span class="bold">净额</span>
                                            <span class="bold">其他</span>
                                        </td>
                                        <td>
                                            <div class="market-container scroll-x">
                                                <div class="item" v-for="(item,index) in industry_datas">
                                                    <span>{{item[1]}}</span>
                                                    <span>{{item[3]}}</span>
                                                    <span>{{item[2]}}</span>
                                                </div>
                                            </div>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
@@ -309,42 +304,68 @@
            <!-- 文档流 第二块 -->
            <!-- 首板梯队 -->
            <div>
                <div class="table-name plate-container" style="float: left;width: 100%;text-align: center; background: #000;">
                    <span v-for="(item,i) in first_info.limit_up_reason_statistic" v-on:click="show_want_codes(item[0])">
                <!-- 待买池 -->
                <div class="table-name plate-container"
                    style="float: left;width: 100%;text-align: center; background: #000;height:60px">
                    <span v-for="(item,i) in first_info.limit_up_reason_statistic"
                        v-on:click="show_want_codes(item[0])">
                        <span class="num-style red">{{item[0]}}({{item[1]}}&{{item[2]}})</span>&nbsp;&nbsp;&nbsp;&nbsp;
                    </span>
                </div>
                <!-- 左侧 -->
                <div style="float: left;width: 27.5%;margin-right: 0.4%;" class="scroll-y">
                    <table style="width: 100%; background: #cecece;" class="shoubanzuogundong">
                        <thead></thead>
                        <tbody>
                            <tr v-for="(item,index) in first_info.limit_up_codes" @click="select_code_level_1($event,index)" :class="{'active':choose_code.first==item[0]}">
                            <tr v-for="(item,index) in first_info.limit_up_codes"
                                @click="select_code_level_1($event,index)"
                                :class="{'active':choose_code.first==item[0]}">
                                <td>
                                    <div>
                                        <span v-if="item[2]==1"><img src="./images/limit_up.png"></span>
                                        <span v-else-if="item[2]==2"><img src="./images/stop_up.png"></span>
                                        <span v-else style="visibility: hidden;"><img src="./images/stop_up.png"></span>
                                    <span
                                            class="num-style"  :class="{'green': item[0].indexOf('00')!=0&&item[0].indexOf('60')!=0 }">{{item[1]}}</span><span class="num-card-red"
                                            v-if="item[3]">{{item[3]}}</span><span class="num-card-bule"
                                            v-if="item[4]">{{item[4]}}</span><span class="score-card-color yellow"
                                            v-if="item[5]">{{item[5]}}</span>
                                    <div style="display:flex;justify-content:space-between;align-items:center">
                                        <div>
                                            <span v-if="item[2]==1"><img src="./images/limit_up.png"></span>
                                            <span v-else-if="item[2]==2"><img src="./images/stop_up.png"></span>
                                            <span v-else style="visibility: hidden;"><img
                                                    src="./images/stop_up.png"></span>
                                            <span class="num-style"
                                                :class="{'green': item[0].indexOf('00')!=0&&item[0].indexOf('60')!=0 }">{{item[1]}}</span><span
                                                class="num-card-red" v-if="item[3]">{{item[3]}}</span><span
                                                class="num-card-bule" v-if="item[4]">{{item[4]}}</span><span
                                                class="score-card-color yellow" v-if="item[5]">{{item[5]}}</span>
                                        </div>
                                        <div>
                                            <span class="num-style red">{{item[6]}}</span>
                                        </div>
                                    </div>
                                    <img class="delete" src="./images/delete.png" alt=""
                                        style="float: right;margin-top: 6px;margin-right: -8px;" @click="del_code_level_1(index)">
                                    <div><span class="num-style red">{{item[6]}}</span>&nbsp;&nbsp;&nbsp;&nbsp;<span
                                            class="bule">{{item[7]}}</span>(<span
                                            class="num-style red">{{item[8]}}</span>)
                                        style="float: right;margin-top: 12px;margin-right: -8px;"
                                        @click="del_code_level_1(index)">
                                    <div style="display:flex;justify-content:space-between;align-items:center">
                                        <div>
                                            <span class="bule">{{item[7]}}</span>(<span
                                                class="num-style red">{{item[8]}}</span>)
                                            <!-- 净流入 -->
                                            <span v-if="item[11]">
                                                &&nbsp;<span class="num-style red">{{item[11]}}</span>
                                            </span>
                                            <span v-if="item[10]">&{{item[10]}}</span>
                                            </div>
                                        </div>
                                    </div>
                                    <div>代码:<span class="num-style">{{item[0]}}</span>&nbsp;&nbsp;&nbsp;&nbsp;自由市值:<span
                                            class="num-style">{{item[9]}}</span></div>
                                    <!-- 交易信息 -->
                                    <div class="num-style" style="font-size:12px;overflow: hidden;width:260px;" v-html="item[12]"></div>
                                </td>
                            </tr>
@@ -357,41 +378,56 @@
                <!-- 右侧 -->
                <div style="float: right; width:72%;" v-if="choose_code_info" >
                <div style="float: right; width:72%;" v-if="choose_code_info">
                    <!-- 右侧固定位 -->
                    <div >
                        <table style="float: right; width:100%; background: #EEE;height: 130px; max-height: 130px;min-height: 130px; overflow: hidden;">
                    <div>
                        <table
                            style="float: right; width:100%; background: #EEE;height: 130px; max-height: 130px;min-height: 130px; overflow: hidden;">
                            <thead></thead>
                            <tbody>
                                <tr>
                                <tr style="display: none;">
                                    <td style="width: 10%;"><span class="bold">强度</span></td>
                                    <td colspan="3">
                                        <div class="scroll-x" style="width: 670px;">
                                        <div style="display: inline-block; margin-right: 16px;"
                                            v-for="(item,index) in choose_code_info.plat_strength"><span
                                                class="num-style">{{item[1]}}</span><br><span
                                                class="num-style">{{item[2]}}</span>
                                        </div>
                                            <div style="display: inline-block; margin-right: 16px;"
                                                v-for="(item,index) in choose_code_info.plat_strength"><span
                                                    class="num-style">{{item[1]}}</span><br><span
                                                    class="num-style">{{item[2]}}</span>
                                            </div>
                                        </div>
                                    </td>
                                </tr>
                                <tr>
                                    <td><span class="bold">今天</span></td>
                                    <td><span v-if="choose_code_info.today">
                                        <span class="red">【{{choose_code_info.today[0]}}】</span>|&nbsp;<span class="num-style">{{choose_code_info.today[2]}}</span></td>
                                            <span class="red">【{{choose_code_info.today[0]}}】</span>|&nbsp;<span
                                                class="num-style">{{choose_code_info.today[2]}}</span>
                                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;二级:
                                            <span class="num-style">
                                                {{choose_code_info.industry}}
                                            </span>
                                    </td>
                                </tr>
                                <tr>
                                    <td><span class="bold">历史</span></td>
                                    <td>
                                            <span v-for="(item1,i1) in choose_code_info.code_records">
                                                <span class="num-style red">【{{item1[0]}}】</span>|&nbsp;<span
                                                    class="num-style">{{item1[2]}}</span><span
                                                    class="num-style">({{item1[1]}})</span>
                                                &nbsp;&nbsp;&nbsp;&nbsp;
                                            </span>
                                        <span v-for="(item1,i1) in choose_code_info.code_records">
                                            <span class="num-style red">【{{item1[0]}}】</span>|&nbsp;<span
                                                class="num-style">{{item1[2]}}</span><span
                                                class="num-style">({{item1[1]}})</span>
                                            &nbsp;&nbsp;&nbsp;&nbsp;
                                        </span>
                                    </td>
@@ -411,101 +447,121 @@
                            </tbody>
                            <tfoot></tfoot>
                        </table>
                        <div style="float: right; width:100%;background: #cecece;height: 10px;"></div>
                        <div style="float: right; width:100%;background: #cecece;height: 10px;"></div>
                    </div>
                    <!-- 右侧滚动表格 -->
                    <div class="outer-container scroll-y" style="float: right;">
                        <div class="daixuan" v-for="(item,i) in choose_code_info.code_list_info" @click="select_code_level_2($event,i)" >
                                <!-- 一条信息 -->
                        <table  :class="{'active':choose_code.second==item.code_info[0]}">
                                    <thead></thead>
                                    <tbody>
                                        <div>
                                            <tr>
                                                <td style="width: 10%;"><span
                                                        class="bold" :class="{'purple':item.code_info[11]>8}">{{item.code_info[11]}}%</span></td>
                                                <td colspan="3">
                                                    <div>
                                                        <span v-if="item.code_info[2]==1"><img
                                                                src="./images/limit_up.png"></span>
                                                        <span v-if="item.code_info[2]==2"><img
                                                                src="./images/stop_up.png"></span>
                                                        <span class="num-style bold" :class="{'green': item.code_info[0].indexOf('00')!=0&&item.code_info[0].indexOf('60')!=0 }">{{item.code_info[1]}}</span><span
                                                            class="num-card-red"
                                                            v-if="item.code_info[3]">{{item.code_info[3]}}</span><span
                                                            class="num-card-bule"
                                                            v-if="item.code_info[4]">{{item.code_info[4]}}</span>
                                                            <span v-if="item.code_info[5]"
                                                            class="score-card-color yellow">{{item.code_info[5]}}</span><span
                                                            class="num-card-black"
                                                            v-if="item.code_info[13]">{{item.code_info[13]}}</span>
                                                        <span class="num-card-pink"
                                                            v-if="item.code_info[14]">{{item.code_info[14]}}</span>
                        <div class="daixuan" v-for="(item,i) in choose_code_info.code_list_info"
                            @click="select_code_level_2($event,i)">
                            <!-- 一条信息 -->
                            <table :class="{'active':choose_code.second==item.code_info[0]}">
                                <thead></thead>
                                <tbody>
                                    <div>
                                        <tr>
                                            <td style="width: 10%;"><span class="bold"
                                                    :class="{'purple':item.code_info[11]>8}">{{item.code_info[11]}}%</span>
                                            </td>
                                            <td colspan="3">
                                                    </div>
                                                    <img src="./images/delete.png" alt=""
                                                        style="float: right;margin-right: -2px;" @click="del_code_level_2(i)">
                                                    <div><span
                                                            v-if="item.code_info[6]&& item.code_info[6]!='00:00:00'">涨停时间:<span
                                                                class="num-style red">{{item.code_info[6]}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span>代码:<span
                                                            class="num-style" >{{item.code_info[0]}}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;现价:<span
                                                            class="num-style red">{{item.code_info[12]}}元</span>&nbsp;&nbsp;&nbsp;&nbsp;自由市值:<span
                                            class="num-style red">{{item.code_info[9]}}</span></div>
                                                    <div>主力净值:<span
                                                            class="num-style">{{item.code_info[15]}}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;300W:<span
                                                            class="num-style">{{item.code_info[16]}}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第一季度机构增仓:<span
                                                            class="num-style">{{item.code_info[17]}}</span></div>
                                                </td>
                                                <div>
                                                    <span v-if="item.code_info[2]==1"><img
                                                            src="./images/limit_up.png"></span>
                                                    <span v-if="item.code_info[2]==2"><img
                                                            src="./images/stop_up.png"></span>
                                                    <span class="num-style bold"
                                                        :class="{'green': item.code_info[0].indexOf('00')!=0&&item.code_info[0].indexOf('60')!=0 }">{{item.code_info[1]}}</span><span
                                                        class="num-card-red"
                                                        v-if="item.code_info[3]">{{item.code_info[3]}}</span><span
                                                        class="num-card-bule"
                                                        v-if="item.code_info[4]">{{item.code_info[4]}}</span>
                                                    <span v-if="item.code_info[5]"
                                                        class="score-card-color yellow">{{item.code_info[5]}}</span><span
                                                        class="num-card-black"
                                                        v-if="item.code_info[13]">{{item.code_info[13]}}</span>
                                                    <span class="num-card-pink"
                                                        v-if="item.code_info[14]">{{item.code_info[14]}}</span>
                                            </tr>
                                            <tr>
                                                <td><span class="bold">今天</span></td>
                                                <td>
                                                        <span v-if="item.today">
                                                            <span class="red">【{{item.today[0]}}】</span>|&nbsp;<span class="num-style">{{item.today[2]}}</span>
                                                        </span>
                                                </div>
                                                <img src="./images/delete.png" alt=""
                                                    style="float: right;margin-right: -2px;"
                                                    @click="del_code_level_2(i)">
                                                <div><span
                                                        v-if="item.code_info[6]&& item.code_info[6]!='00:00:00'">涨停时间:<span
                                                            class="num-style red">{{item.code_info[6]}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span>代码:<span
                                                        class="num-style">{{item.code_info[0]}}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;现价:<span
                                                        class="num-style red">{{item.code_info[12]}}元</span>&nbsp;&nbsp;&nbsp;&nbsp;自由市值:<span
                                                        class="num-style red">{{item.code_info[9]}}</span></div>
                                                <div>主力净值:<span
                                                        class="num-style">{{item.code_info[15]}}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;300W:<span
                                                        class="num-style">{{item.code_info[16]}}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第一季度机构增仓:<span
                                                        class="num-style">{{item.code_info[17]}}</span></div>
                                            </td>
                                                </td>
                                        </tr>
                                        <tr
                                            v-if="item.code_info[0].indexOf('00')==0||item.code_info[0].indexOf('60')==0">
                                            <td><span class="bold">今天</span></td>
                                            <td>
                                                <span v-if="item.today">
                                                    <span class="red">【{{item.today[0]}}】</span>|&nbsp;<span
                                                        class="num-style">{{item.today[2]}}</span>
                                                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                                                </span>
                                            </tr>
                                            <tr>
                                                <td><span class="bold">历史</span></td>
                                                <td style="max-width: 650px;">
                                                    <div style="display: flex;flex-wrap: wrap;border-width: 1px;">
                                                二级:
                                                <span class="num-style">
                                                    {{item.industry}}
                                                </span>
                                            </td>
                                        </tr>
                                        <tr
                                            v-if="item.code_info[0].indexOf('00')==0||item.code_info[0].indexOf('60')==0">
                                            <td><span class="bold">历史</span></td>
                                            <td style="max-width: 650px;">
                                                <div style="display: flex;flex-wrap: wrap;border-width: 1px;">
                                                    <span v-for="(item1,i1) in item.code_records">
                                                        <span class="num-style red">【{{item1[0]}}】</span>|&nbsp;<span
                                                            class="num-style">{{item1[2]}}</span><span
                                                        <span class="num-style red">【{{item1[0][0]}}】</span>|&nbsp;
                                                        <span v-for="(item2,i2) in item1[2]">
                                                            <span>{{item2[0]}}</span><span v-if="i2!=item1[2].length -1">、</span>
                                                        </span>
                                                            <span
                                                            class="num-style">({{item1[1]}})</span>
                                                        &nbsp;&nbsp;&nbsp;&nbsp;
                                                    </span>
                                                </div>
                                            </td>
                                        </tr>
                                        <tr
                                            v-if="item.code_info[0].indexOf('00')==0||item.code_info[0].indexOf('60')==0">
                                            <td><span class="bold">板块</span></td>
                                            <td>
                                                <div class="scroll-x" style="width: 650px;">
                                                    <div v-for="(item1,i1) in item.plate" class="item">
                                                        <span class="num-style line"
                                                            style="display: block;">{{item1[1]}}</span>
                                                        <span class="num-style line"
                                                            style="display: block;">{{item1[2]}}%</span>
                                                    </div>
                                                </td>
                                                </div>
                                            </td>
                                            </tr>
                                            <tr>
                                                <td><span class="bold">板块</span></td>
                                                <td>
                                                    <div class="scroll-x" style="width: 650px;">
                                                        <div v-for="(item1,i1) in item.plate" class="item">
                                                            <span class="num-style line" style="display: block;">{{item1[1]}}</span>
                                                            <span class="num-style line" style="display: block;">{{item1[2]}}%</span>
                                                        </div>
                                                    </div>
                                                </td>
                                        </tr>
                                    </div>
                                </tbody>
                                <tfoot></tfoot>
                            </table>
                        </div>
                                            </tr>
                                        </div>
                                    </tbody>
                                    <tfoot></tfoot>
                                </table>
                        </div>
                    </div>
                </div>
@@ -515,39 +571,42 @@
            </div>
            <div style="position: fixed;bottom: 10px;right: 10px;">
                <div style="display: flex;">
                    <span id="" class="button-normal" style="display: inline-block;" @click="do_action_for_code(0)">加入黑名单
                    <span id="" class="button-normal" style="display: inline-block;"
                        @click="do_action_for_code(0)">加入黑名单
                    </span>
                    <span id="" class="button-normal"
                        style="display: inline-block;float: right;"  @click="do_action_for_code(1)">移出黑名单
                    <span id="" class="button-normal" style="display: inline-block;float: right;"
                        @click="do_action_for_code(1)">移出黑名单
                    </span>
                    <span id="" class="button-normal" style="display: inline-block;"  @click="do_action_for_code(2)">加入自选
                    <span id="" class="button-normal" style="display: inline-block;" @click="do_action_for_code(2)">加入自选
                    </span>
                    <span id="" class="button-normal"
                        style="display: inline-block;float: right;"  @click="do_action_for_code(3)">移出自选
                    <span id="" class="button-normal" style="display: inline-block;float: right;"
                        @click="do_action_for_code(3)">移出自选
                    </span>
                    <span id="" class="button-normal" style="display: inline-block;"  @click="do_action_for_code(4)">加入想买单
                    <span id="" class="button-normal" style="display: inline-block;"
                        @click="do_action_for_code(4)">加入想买单
                    </span>
                    <span id="" class="button-normal"
                        style="display: inline-block;float: right;"  @click="do_action_for_code(5)">移出想买单
                    <span id="" class="button-normal" style="display: inline-block;float: right;"
                        @click="do_action_for_code(5)">移出想买单
                    </span>
                </div>
            </div>
            <!-- 弹出框 -->
            <!-- 弹出框 -->
            <div id="want_code_dialog" style="display: none;">
                <div v-if="want_codes" class="want_code_content">
                <div v-for="(item,i) in want_codes" class="item">
                    <div>{{item}}</div>
                    <img class="delete" src="./images/delete.png" @click="delete_from_want_codes(i)">
                <div v-if="want_codes" class="want_code_content" style="display: flex;width: 400px;justify-content: space-between;">
                    <div v-for="(item,i) in want_codes" class="item" style="display: flex;width: 180px;margin-bottom: 15px;">
                        <div>{{item[1]}}({{item[0]}}) <span class="red" v-if="item[2]==1">*</span> </div>
                        <img v-if="item[2]==1" class="delete" src="./images/delete.png"
                            @click="delete_from_want_codes(i)">
                    </div>
                </div>
                </div>
            </div>
        </div>
        <script src="js/page.js"></script>
        <script src="js/page.js?_=1"></script>
    </body>
</html>
kp_html/kp/js/code_list.js
New file
@@ -0,0 +1,79 @@
var app;
$(function() {
    new VConsole();
    app = new Vue({
        el: "#app",
        data: {
            code: "000000",
            code_name: "测试代码",
            trade_data: {},
            trade_record: {
                open_limit_up: "",
                records: []
            },
        },
        methods: {
            set_trade_info: function(code, code_name, trade_data, trade_record, initiative_buy_codes,
                passive_buy_codes) {
                console.log("交易数据", code, code_name, trade_data, trade_record)
                console.log("主动买入", initiative_buy_codes)
                console.log("被动买入", passive_buy_codes)
                app.code = code;
                app.code_name = code_name;
                if (trade_data) {
                    var trade_data = JSON.parse(trade_data);
                    app.trade_data = trade_data
                } else {
                    app.trade_data = {
                        "star": {
                            "desc": "----",
                            "count": 0
                        },
                        "safe_count": {
                            "base": 0,
                            "now": 0
                        },
                        "m_val": {
                            "base": 0,
                            "now": 0
                        },
                        "big_num": {
                            "base": 0,
                            "now": 0
                        },
                        "trade_progress": {
                            "time": "00:00:00",
                            "num": 0,
                            "money": 0
                        },
                        "trade_state": {
                            "order": false,
                            "desc": "未交易"
                        }
                    };
                }
                if (trade_record) {
                    app.trade_record = JSON.parse(trade_record);
                } else {
                    app.trade_record = null;
                }
                if (initiative_buy_codes) {
                    app.initiative_buy_codes = JSON.parse(initiative_buy_codes);
                } else {
                    app.initiative_buy_codes = null;
                }
                if(passive_buy_codes){
                    app.passive_buy_codes = JSON.parse(passive_buy_codes);
                }else{
                    app.passive_buy_codes = null;
                }
            }
        }
    })
});
kp_html/kp/js/http.js
@@ -1,124 +1,155 @@
var http_util={
     request_callback:{},
     getQueryString:function(name) {
        var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
        var r = window.location.search.substr(1).match(reg);
        if (r != null) {
            return  unescape(decodeURI(r[2]));
        }
        return null;
var http_util = {
    request_callback: {},
    getQueryString: function(name) {
        var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
        var r = window.location.search.substr(1).match(reg);
        if (r != null) {
            return unescape(decodeURI(r[2]));
        }
        return null;
    },
    http_request_result:function(key,data){
        console.log("http请求回调","key:"+key);
    http_request_result: function(key, data) {
        console.log("http请求回调", "key:" + key);
        http_util.request_callback[key](data);
        delete http_util.request_callback[key];
    },
    http_request:function(path,data,callback){
        key ="http_callback_"+ new Date().getTime() + "_" + Math.round(Math.random() * 100000000);
    http_request: function(path, data, callback) {
        key = "http_callback_" + new Date().getTime() + "_" + Math.round(Math.random() * 100000000);
        http_util.request_callback[key] = callback;
        pyjs.http_request(path,JSON.stringify(data),JSON.stringify(["http_util.http_request_result",key]));
        pyjs.http_request(path, JSON.stringify(data), JSON.stringify(["http_util.http_request_result", key]));
    },
    get_score_data:function(code,name,callback){
        params={code:code}
        if(name){
            params.name=name;
    get_score_data: function(code, name, callback) {
        params = {
            code: code
        }
        http_util.http_request("/get_score_info",params,callback);
        if (name) {
            params.name = name;
        }
        http_util.http_request("/get_score_info", params, callback);
    },
    get_kpl_data:function(callback){
        http_util.http_request("/get_kpl_data",{},callback);
    get_kpl_data: function(callback) {
        http_util.http_request("/get_kpl_data", {}, callback);
    },
    get_market_data:function(type,callback){
        http_util.http_request("/kpl/get_market_data",{type:type},callback);
    get_market_data: function(type, callback) {
        http_util.http_request("/kpl/get_market_data", {
            type: type
        }, callback);
    },
    get_limit_up_list:function(code,callback){
        http_util.http_request("/kpl/get_limit_up_list",{code:code},callback);
    get_limit_up_list: function(code, callback) {
        http_util.http_request("/kpl/get_limit_up_list", {
            code: code
        }, callback);
    },
    get_plate_info:function(code,callback){
        http_util.http_request("/kpl/get_plate_info",{code:code},callback);
    get_plate_info: function(code, callback) {
        http_util.http_request("/kpl/get_plate_info", {
            code: code
        }, callback);
    },
    add_ignore_code:function(type,code,callback){
        http_util.http_request("/kpl/add_ignore_code",{code:code,type:type},callback);
    add_ignore_code: function(type, code, callback) {
        http_util.http_request("/kpl/add_ignore_code", {
            code: code,
            type: type
        }, callback);
    },
    do_action_for_code:function(code,plate,type,callback){
        var data={"data":{"codes":[code]}};
        var type_desc="";
        switch(type){
    do_action_for_code: function(code, plate, type, callback) {
        var data = {
            "data": {
                "codes": [code]
            }
        };
        var type_desc = "";
        switch (type) {
            case 0:
            //加入黑名单
            data.type=201;
            type_desc="加入黑名单"
            break;
            //移除黑名单
                //加入黑名单
                data.type = 201;
                type_desc = "加入黑名单"
                break;
                //移除黑名单
            case 1:
            data.type=203;
            type_desc="移除黑名单"
            break;
                data.type = 203;
                type_desc = "移除黑名单"
                break;
            case 2:
            //加自选
            data.type=601;
            type_desc="加自选"
            break;
                //加自选
                data.type = 601;
                type_desc = "加自选"
                break;
            case 3:
            //移除自选
            data.type=602;
            type_desc="移除自选"
            break;
                //移除自选
                data.type = 602;
                type_desc = "移除自选"
                break;
            case 4:
            data.type=401;
            data.data.plates=[plate]
            type_desc="加想买"
            //加想买
            break;
                data.type = 401;
                data.data.plates = [plate]
                type_desc = "加想买"
                //加想买
                break;
            case 5:
            data.type=402;
            type_desc="移除想买"
            //移除想买
            break;
                data.type = 402;
                type_desc = "移除想买"
                //移除想买
                break;
        }
        console.log("socket请求",data)
        pyjs.socket_request(JSON.stringify(data),function(result){
            result=JSON.parse(result);
            if(result.code==0){
        console.log("socket请求", data)
        pyjs.socket_request(JSON.stringify(data), function(result) {
            result = JSON.parse(result);
            if (result.code == 0) {
                // pyjs.show_info(type_desc +"成功");
                layer.msg(type_desc +"成功")
                layer.msg(type_desc + "成功")
            }
            callback(result);
        });
    },
    get_want_codes:function(plate,callback){
        pyjs.socket_request(JSON.stringify({type:403,plate:plate}),function(result){
            result=JSON.parse(result);
            if(result.code==0){
    get_want_codes: function(plate, callback) {
        pyjs.socket_request(JSON.stringify({
            type: 403,
            plate: plate
        }), function(result) {
            result = JSON.parse(result);
            if (result.code == 0) {
                callback(result);
            }
        });
    },
    cancel_order:function(code,success){
        var data = {"type": 80, "data": {"code": code}};
        pyjs.socket_request(JSON.stringify(data),function(result){
            result=JSON.parse(result);
            if(result.code==0){
    cancel_order: function(code, success) {
        var data = {
            "type": 80,
            "data": {
                "code": code
            }
        };
        pyjs.socket_request(JSON.stringify(data), function(result) {
            result = JSON.parse(result);
            if (result.code == 0) {
                success()
            }
        });
    },
    forbidden_plate: function(plate, callback) {
        http_util.http_request("/kpl/forbidden_plate", {
            plate: plate
        }, callback);
    },
    // 获取板块下的代码
    get_plate_codes: function(plate, callback) {
        http_util.http_request("/kpl/get_plate_codes", {
            plate: plate
        }, callback);
    }
};
};
kp_html/kp/js/page.js
@@ -14,9 +14,9 @@
$(function() {
    function _resize() {
        console.log("总高", $(window).height())
        var bottom_height = $(window).height() - 450 - 80;
        var bottom_height = $(window).height() - 465 - 110;
        console.log("底部高", bottom_height)
        $("#body>div:nth-child(2)>div").css("height",450).css("max-height",450);
        $("#body>div:nth-child(2)>div").css("height", 465).css("max-height", 465);
        $("#body>div:nth-child(3)").css("height", bottom_height)
        $("#body>div:nth-child(3)>div:nth-child(2)").css("height", bottom_height - 10)
        $("#body>div:nth-child(3)>div:nth-child(3)").css("height", bottom_height - 60)
@@ -68,6 +68,7 @@
    setInterval(function() {
        if (is_trade_time()) {
            app.get_industry_data(app.industry_data_type);
            app.get_jingxuan_data(app.jingxuan_data_type);
        }
    }, 3000, 10000);
@@ -201,14 +202,14 @@
                },
                kpl_code_info: {
                    code_records: [
                        ["原因", "2020-01-01", "板块"],
                        ["原因", "2020-01-01", "板块"],
                        ["原因", "2020-01-01", "板块"]
                        [["原因",''], "2020-01-01", [["板块",'']]],
                        [["原因",''], "2020-01-01", [["板块",'']]],
                        [["原因",''], "2020-01-01", [["板块",'']]]
                    ],
                    today: ["涨停原因", "2023-01-01", "传媒"],
                    today: [["涨停原因",''], "2023-01-01", [["传媒",'']]],
                    plate: [
                        ["板块1", "1%"],
                        ["板块2", "0.5%"]
                        ["板块1", "1%",''],
                        ["板块2", "0.5%",'']
                    ]
                },
                initiative_buy_codes: [{
@@ -246,13 +247,14 @@
                industry_datas: [
                    ["贵金属", "1.56亿", "0.9%"]
                ],
                jingxuan_datas: [],
                //涨停代码信息
                first_info: {
                    limit_up_count: 10,
                    open_limit_up_count: 10,
                    limit_up_codes: [
                        //(代码,名称,涨停状态(0-无状态 1-涨停 2-炸板),龙几,首板,分值,涨停时间,原因,相同原因代码数量,自由流通,之前的板块)
                        ["000333", "美的集团", 1, "龙1", "首板", "200", "10:00:00", "一季度增长", "1", "12.02亿",
                        ["000333", "美的集团", 1, "龙1", "首板", "200", "10:00:00", "一季度增长", "1", "12.02亿",'12亿','',
                            ''
                        ],
                        ["000333", "美的集团", 1, "龙1", "首板", "200", "10:00:00", "一季度增长", "1", "12.02亿",
@@ -332,7 +334,8 @@
                    first: '',
                    second: ''
                },
                industry_data_type: 2
                industry_data_type: 0,
                jingxuan_data_type: 0,
            },
            methods: {
@@ -356,10 +359,26 @@
                        }
                    });
                },
                get_score_data: function(code,name, callback) {
                    http_util.get_score_data(code,name, function(res) {
                get_jingxuan_data: function(type) {
                    app.jingxuan_data_type = type;
                    if (type == 0) {
                        type = 2;
                    } else {
                        type = 3;
                    }
                    http_util.get_market_data(type, function(result) {
                        result = JSON.parse(result);
                        if (result.code == 0) {
                            app.jingxuan_datas = result.data;
                        }
                    });
                },
                get_score_data: function(code, name, callback) {
                    console.log("获取分数数据:", code, name);
                    http_util.get_score_data(code, name, function(res) {
                        res = JSON.parse(res)
                        console.log(res)
                        console.log("分数请求结果:", res)
                        if (res.code == 0) {
                            console.log("获取分数", res)
                            app.code = res.data.code
@@ -386,7 +405,11 @@
                            pyjs.set_trade_info(app.code, app.code_name, res.data
                                .trade_data ? JSON.stringify(res.data.trade_data) : "",
                                res.data.trade_record ? JSON.stringify(res.data
                                    .trade_record) : '');
                                    .trade_record) : '', res.data
                                .initiative_buy_codes ? JSON.stringify(res.data
                                    .initiative_buy_codes) : '', res.data
                                .passive_buy_codes ? JSON.stringify(res.data
                                    .passive_buy_codes) : '');
                            if (callback) {
                                callback()
@@ -430,12 +453,25 @@
                    });
                },
                cancel_order: function() {
                    if (!trade_data.order) {
                        return;
                    }
                    // if (!trade_data.order) {
                    //     return;
                    // }
                    http_util.cancel_order(app.code, function() {
                        //撤单成功,刷新代码
                        app.get_score_data(app.code,null);
                        app.get_score_data(app.code, null);
                    });
                },
                forbidden_plate: function(plate, type) {
                    http_util.forbidden_plate(plate, function(res) {
                        res = JSON.parse(res)
                        if (res.code == 0) {
                            layer.msg("删除成功");
                            if (type == 0) {
                                app.get_industry_data(app.industry_data_type);
                            } else {
                                app.get_jingxuan_data(app.jingxuan_data_type);
                            }
                        }
                    });
                },
                //选中1级代码
@@ -443,7 +479,8 @@
                    var el = event.currentTarget;
                    if (app.choose_code.first != app.first_info.limit_up_codes[index][0]) {
                        app.choose_code.first = app.first_info.limit_up_codes[index][0];
                        app.get_score_data(app.first_info.limit_up_codes[index][0],app.first_info.limit_up_codes[index][1]);
                        app.get_score_data(app.first_info.limit_up_codes[index][0], app.first_info
                            .limit_up_codes[index][1]);
                        app.get_plate_info(app.first_info.limit_up_codes[index][0]);
                    }
                },
@@ -469,7 +506,8 @@
                            .code_info[0])
                        app.choose_code.second = app.choose_code_info.code_list_info[index]
                            .code_info[0];
                        app.get_score_data(app.choose_code_info.code_list_info[index].code_info[0],app.choose_code_info.code_list_info[index].code_info[1],
                        app.get_score_data(app.choose_code_info.code_list_info[index].code_info[0],
                            app.choose_code_info.code_list_info[index].code_info[1],
                            function() {
                                app.choose_code_info.code_list_info[index].code_records = app
                                    .kpl_code_info.code_records;
@@ -478,10 +516,14 @@
                                    .plate;
                                app.$set(app.choose_code_info.code_list_info, index, app
                                    .choose_code_info.code_list_info[index]);
                                //暂存选中二级代码数据
                                app.choose_code.second_info.code_records = app.kpl_code_info
                                    .code_records;
                                app.choose_code.second_info.plate = app.kpl_code_info.plate;
                                if (app.choose_code.second_info)
                                {
                                    //暂存选中二级代码数据
                                    app.choose_code.second_info.code_records = app.kpl_code_info
                                        .code_records;
                                    app.choose_code.second_info.plate = app.kpl_code_info.plate;
                                }
                            });
                    }
                },
@@ -514,18 +556,21 @@
                    http_util.do_action_for_code(app.code, plate, type, function(result) {});
                },
                set_target_code: function(code) {
                    console.log("set_target_code", code);
                    console.log("设置目标代码", code);
                    app.origin_code = code;
                    app.code = code;
                    init_data();
                },
                show_want_codes: function(plate) {
                    http_util.get_want_codes(plate, function(result) {
                        datas = result.data;
                    http_util.get_plate_codes(plate, function(result) {
                        result = JSON.parse(result);
                        console.log("涨停原因成分股返回:",result);
                        var datas = result.data;
                        app.want_codes = datas;
                        console.log("涨停原因成分股:",datas)
                        setTimeout(function() {
                            layer.open({
                                title: "想买单(" + plate + ")",
                                title:  plate,
                                type: 1,
                                content: $("#want_code_dialog"),
                            })
@@ -539,15 +584,14 @@
                },
                delete_from_want_codes: function(index) {
                    http_util.do_action_for_code(app.want_codes[index].split(":")[1], "", 5,
                    http_util.do_action_for_code(app.want_codes[index][0], "", 5,
                        function(result) {
                            if (result.code == 0) {
                                app.want_codes.splice(index, 1);
                                app.want_codes[index][2]=0;
                                app.$set(app.want_codes,index,app.want_codes[index]);
                                app.get_limit_up_list(app.code, true);
                            }
                        });
                }
            }
        });
@@ -555,6 +599,7 @@
    function init_data() {
        app.get_industry_data(app.industry_data_type);
        app.get_jingxuan_data(app.jingxuan_data_type);
        app.get_score_data(app.code);
        app.get_limit_up_list(app.code, false);
    }
kp_html/kp/test.html
@@ -1,47 +1,126 @@
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style>
            .body{
                height: 100%;
                display: flex;
                flex-direction: column;
                align-items: stretch;
            }
            .d1{
                background: red;
                height: 50px;
            }
            .d2{
                background: blue;
                height: 200px;
            }
            .d3{
                background: yellow;
                flex-grow: 1;
                height: 500px;
                overflow: hidden;
                overflow-y: auto;
                white-space: nowrap;
                outline: none;
            }
        </style>
    </head>
    <body>
        <div class="body">
            <div class="d1"></div>
            <div class="d2"></div>
            <div class="d3">
                <div style="height: 1000px; background: yellow;"></div>
            </div>
        </div>
    </body>
</html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>用户登录</title>
  <style>
    body {
      font-family: "宋体", Arial, Helvetica, sans-serif;
      background-color: #FEEFE3;
      background-image: url("https://i.imgur.com/9NyJSkH.jpg");
      background-size: 800px;
      background-repeat: no-repeat;
      background-position: center top;
    }
    * {
      box-sizing: border-box;
    }
    /* Add padding to container elements */
    .container {
      padding: 20px;
      background-color: rgba(255, 255, 255, 0.8);
      border-radius: 20px;
      width: 380px;
      margin: auto;
      margin-top: 15vh;
      box-shadow: 10px 10px 40px rgba(0, 0, 0, 0.2);
    }
    /* Full-width input fields */
    input[type=text],
    input[type=password] {
      width: 100%;
      padding: 12px 20px;
      margin: 8px 0;
      display: inline-block;
      border: none;
      background-color: #FEEFE3;
      border-radius: 8px;
      font-size: 18px;
    }
    /* Set a style for the submit button */
    button {
      background-color: #F53A20;
      color: white;
      padding: 16px 20px;
      margin: 20px 0;
      border: none;
      cursor: pointer;
      width: 100%;
      border-radius: 8px;
      font-size: 24px;
      letter-spacing: 2px;
    }
    /* Set a hover effect for the submit button */
    button:hover {
      opacity: 0.8;
    }
    /* Center the login form */
    .login-form {
      text-align: center;
      font-size: 24px;
      margin-bottom: 20px;
    }
    /* Add a red border to invalid inputs */
    input:invalid {
      border-color: #E91E63;
    }
    /* Style for the heading */
    h1 {
      font-size: 48px;
      color: #F53A20;
      text-shadow: 3px 3px 6px rgba(0, 0, 0, 0.2);
      text-align: center;
      margin-top: 80px;
    }
    /* Style for the input labels */
    label {
      font-size: 24px;
      color: #FFC400;
      display: block;
      text-align: left;
      margin-bottom: 8px;
      letter-spacing: 2px;
    }
    /* Style for the error message */
    .error {
      color: #E91E63;
      font-size: 18px;
      text-align: left;
      margin-top: 8px;
    }
  </style>
</head>
<body>
  <h1>中国风登录页面</h1>
  <form class="login-form" action="" method="post">
    <div class="container">
      <label for="username">用户名</label>
      <input type="text" placeholder="请输入用户名" name="username" required>
      <label for="password">密码</label>
      <input type="password" placeholder="请输入密码" name="password" required>
      <button type="submit">登录</button>
      <div class="error">用户名或密码错误</div>
    </div>
  </form>
</body>
</html>
main.py
@@ -204,6 +204,10 @@
        def __show_second_window():
            self.secondWindow.show()
        # 清除浏览器缓存
        def __clear_webview_cache():
            self.webview.page().profile().clearHttpCache()
        menubar = self.menuBar()
        setting_ = menubar.addMenu('&设置')
@@ -224,6 +228,10 @@
        action.triggered.connect(__gpu_is_avaiable)
        setting_.addAction(action)
        action = QAction("&清除浏览器缓存", self)
        action.triggered.connect(__clear_webview_cache)
        setting_.addAction(action)
        auto_ = menubar.addMenu('&自动化')
        action = QAction("&同花顺设置", self)
        action.triggered.connect(__manage_ths_pos)
res/setting.conf
@@ -1,10 +1,10 @@
[config]
stay_on_top = 1
window_info = [[-1711, 194, 1280, 800], [1473, 621, 320, 195]]
xgb_window_info = [-759, 198, 2253, 1017]
xgb_window_info = [-1921, -8, 1920, 1017]
window_watch_float_info = [1178, 372, 320, 195]
window_tick_info = [-1919, 1, 1918, 1038]
kp_second_window_info = [90, 201, 694, 800]
kp_second_window_info = [363, 160, 738, 890]
[juejin]
strategy_id = 95a982ce-fc2d-11ec-8ff3-0a0027000010
test.png

ths_util.py
@@ -32,9 +32,14 @@
def get_trade_refesh_hwnd():
    hwnds = win32_util.search_window("网上股票交易系统")
    if hwnds:
        hwnd = hwnds[0]
        hwnd = win32gui.FindWindowEx(hwnd, None, "ToolbarWindow32", None)
        return hwnd
        for hwnd in hwnds:
            hwnd = win32gui.FindWindowEx(hwnd, None, "ToolbarWindow32", None)
            temp = win32gui.FindWindowEx(hwnd, None, "#32770", None)
            if temp:
                nq = win32gui.FindWindowEx(temp, None, None, "内嵌")
                if nq and win32gui.IsWindowVisible(nq):
                    continue
            return hwnd
    return None
@@ -64,4 +69,4 @@
if __name__ == "__main__":
    win32_util.visual_keyboard(get_trade_refesh_hwnd(), win32con.VK_F5)
    print(get_trade_refesh_hwnd())