tk_自動化

-- encoding: utf8 --

version 1.11

import tkinter.messagebox,os
from tkinter import *
from tkinter.ttk import *
from tkinter import Menu
import datetime
import threading
import pickle
import time
import tushare as ts
import pywinauto
import pywinauto.clipboard
import pywinauto.application
NUM_OF_STOCKS = 5 # 自定義股票數(shù)量
is_start = False
is_monitor = True
set_stocks_info = []
actual_stocks_info = []
consignation_info = []
is_ordered = [1] * NUM_OF_STOCKS # 1:未下單 0:已下單
is_dealt = [0] * NUM_OF_STOCKS # 0: 未成交 負(fù)整數(shù):賣出數(shù)量, 正整數(shù):買入數(shù)量
stock_codes = [''] * NUM_OF_STOCKS

class OperationThs:
def init(self):
try:
self.__app = pywinauto.application.Application()
self.__app.connect(title='網(wǎng)上股票交易系統(tǒng)5.0')
top_hwnd = pywinauto.findwindows.find_window(title='網(wǎng)上股票交易系統(tǒng)5.0')
dialog_hwnd = pywinauto.findwindows.find_windows(top_level_only=False, class_name='#32770', parent=top_hwnd)[0]
wanted_hwnds = pywinauto.findwindows.find_windows(top_level_only=False, parent=dialog_hwnd)
print('wanted_hwnds length', len(wanted_hwnds))
if len(wanted_hwnds) not in (99,97,96,98,100,101):
tkinter.messagebox.showerror('錯誤', '無法獲得“同花順雙向委托界面”的窗口句柄,請將同花順交易系統(tǒng)切換到“雙向委托界面”!')
exit()
self.__main_window = self._app.window(handle=top_hwnd)
self.__dialog_window = self._app.window(handle=dialog_hwnd)
except:
pass
def __buy(self, code, quantity):
"""買函數(shù)
:param code: 代碼, 字符串
:param quantity: 數(shù)量, 字符串
"""
self.__dialog_window.Edit1.SetFocus()
time.sleep(0.2)
self.__dialog_window.Edit1.SetEditText(code)
time.sleep(0.2)
if quantity != '0':
self.__dialog_window.Edit3.SetEditText(quantity)
time.sleep(0.2)
self.__dialog_window.Button1.Click()
time.sleep(0.2)
def __sell(self, code, quantity):
"""
賣函數(shù)
:param code: 股票代碼, 字符串
:param quantity: 數(shù)量, 字符串
"""
self.__dialog_window.Edit4.SetFocus()
time.sleep(0.2)
self.__dialog_window.Edit4.SetEditText(code)
time.sleep(0.2)
if quantity != '0':
self.__dialog_window.Edit6.SetEditText(quantity)
time.sleep(0.2)
self.__dialog_window.Button2.Click()
time.sleep(0.2)
def __closePopupWindow(self):
"""
關(guān)閉一個彈窗。
:return: 如果有彈出式對話框,返回True,否則返回False
"""
popup_hwnd = self.__main_window.PopupWindow()
if popup_hwnd:
popup_window = self._app.window(handle=popup_hwnd)
popup_window.SetFocus()
popup_window.Button.Click()
return True
return False

def __closePopupWindows(self):
    """
    關(guān)閉多個彈出窗口
    :return:
    """
    while self.__closePopupWindow():
        time.sleep(0.5)
def order(self, code, direction, quantity):
    """
    下單函數(shù)
    :param code: 股票代碼, 字符串
    :param direction: 買賣方向, 字符串
    :param quantity: 買賣數(shù)量, 字符串
    """
    if direction == 'B':
        self.__buy(code, quantity)
    if direction == 'S':
        self.__sell(code, quantity)
    self.__closePopupWindows()
def maxWindow(self):
    """
    最大化窗口
    """
    if self.__main_window.GetShowState() != 3:

        self.__main_window.Maximize()
    self.__main_window.SetFocus()

def minWindow(self):
    """
    最小化窗體
    """
    if self.__main_window.GetShowState() != 2:
        self.__main_window.Minimize()

def refresh(self, t=0.5):
    """
    點擊刷新按鈕
    :param t:刷新后的等待時間
    """
    self.__dialog_window.Button5.Click()
    time.sleep(t)
def getMoney(self):
    """
    獲取可用資金
    """
    return float(self.__dialog_window.Static19.WindowText())
@staticmethod
def __cleanClipboardData(data, cols=11):
    """
    清洗剪貼板數(shù)據(jù)
    :param data: 數(shù)據(jù)
    :param cols: 列數(shù)
    :return: 清洗后的數(shù)據(jù),返回列表
    """
    lst = data.strip().split()[:-1]
    matrix = []
    for i in range(0, len(lst) // cols):
        matrix.append(lst[i * cols:(i + 1) * cols])
    return matrix[1:]

def __copyToClipboard(self):
    """
    拷貝持倉信息至剪貼板
    :return:
    """
    self.__dialog_window.CVirtualGridCtrl.RightClick(coords=(30, 30))
    self.__main_window.TypeKeys('C')

def __getCleanedData(self):
    """
    讀取ListView中的信息
    :return: 清洗后的數(shù)據(jù)
    """
    self.__copyToClipboard()
    data = pywinauto.clipboard.GetData()
    return self.__cleanClipboardData(data)

def __selectWindow(self, choice):
    """
    選擇tab窗口信息
    :param choice: 選擇個標(biāo)簽頁。持倉,撤單,委托,成交
    :return:
    """
    rect = self.__dialog_window.CCustomTabCtrl.ClientRect()
    x = rect.width() // 8
    y = rect.height() // 2
    if choice == 'W':
        x = x
    elif choice == 'E':
        x *= 3
    elif choice == 'R':
        x *= 5
    elif choice == 'A':
        x *= 7
    self.__dialog_window.CCustomTabCtrl.ClickInput(coords=(x, y))
    time.sleep(0.5)

def __getInfo(self, choice):
    """
    獲取股票信息
    """
    self.__selectWindow(choice=choice)
    return self.__getCleanedData()

def getPosition(self):
    """
    獲取持倉
    :return:
    """
    return self.__getInfo(choice='W')
@staticmethod
def getDeal(code, pre_position, cur_position):
    """
    獲取成交數(shù)量
    :param code: 需檢查的股票代碼, 字符串
    :param pre_position: 下單前的持倉
    :param cur_position: 下單后的持倉
    :return: 0-未成交, 正整數(shù)是買入的數(shù)量, 負(fù)整數(shù)是賣出的數(shù)量
    """
    if pre_position == cur_position:
        return 0
    pre_len = len(pre_position)
    cur_len = len(cur_position)
    if pre_len == cur_len:
        for row in range(cur_len):
            if cur_position[row][0] == code:
                return int(float(cur_position[row][1]) - float(pre_position[row][1]))
    if cur_len > pre_len:
        return int(float(cur_position[-1][1]))

def withdraw(self, code, direction):
    """
    指定撤單
    :param code: 股票代碼
    :param direction: 方向 B, S
    :return:
    """
    row_pos = []
    info = self.__getInfo(choice='R')
    if direction == 'B':
        direction = '買入'
    elif direction == 'S':
        direction = '賣出'
    if info:
        for index, element in enumerate(info):
            if element[0] == code:
                if element[1] == direction:
                    row_pos.append(index)
    if row_pos:
        for row in row_pos:
            self.__dialog_window.CVirtualGridCtrl.ClickInput(coords=(7, 28 + 16 * row))
        self.__dialog_window.Button12.Click()
        self.__closePopupWindows()

def withdrawBuy(self):
    """
    撤買
    :return:
    """
    self.__selectWindow(choice='R')
    self.__dialog_window.Button8.Click()
    self.__closePopupWindows()

def withdrawSell(self):
    """
    撤賣
    :return:
    """
    self.__selectWindow(choice='R')
    self.__dialog_window.Button9.Click()
    self.__closePopupWindows()

def withdrawAll(self):
    """
    全撤
    :return:
    """
    self.__selectWindow(choice='R')
    self.__dialog_window.Button7.Click()
    self.__closePopupWindows()

def getStockData():
"""
獲取股票實時數(shù)據(jù)
:return:股票實時數(shù)據(jù)
"""
global stock_codes
code_name_price = []
try:
df = ts.get_realtime_quotes(stock_codes)
df_len = len(df)
for stock_code in stock_codes:
is_found = False
for i in range(df_len):
actual_code = df['code'][i]
if stock_code == actual_code:
code_name_price.append((actual_code, df['name'][i], float(df['price'][i])))
is_found = True
break
if is_found is False:
code_name_price.append(('', '', 0))
except:
code_name_price = [('', '', 0)] * NUM_OF_STOCKS # 網(wǎng)絡(luò)不行,返回空
return code_name_price
def monitor():
"""
實時監(jiān)控函數(shù)
"""
global actual_stocks_info, consignation_info, is_ordered, is_dealt, set_stocks_info
count = 1
pre_position = []
try:
operation = OperationThs()
operation.maxWindow()
pre_position = operation.getPosition()
# print(pre_position)
while is_monitor:
if is_start:
actual_stocks_info = getStockData()
for row, (actual_code, actual_name, actual_price) in enumerate(actual_stocks_info):
if actual_code and is_start and is_ordered[row] == 1 and actual_price > 0
and set_stocks_info[row][1] and set_stocks_info[row][2] > 0
and set_stocks_info[row][3] and set_stocks_info[row][4]
and datetime.datetime.now().time() > set_stocks_info[row][5]:
if (set_stocks_info[row][1] == '>' and actual_price > set_stocks_info[row][2]) or
(set_stocks_info[row][1] == '<' and float(actual_price) < set_stocks_info[row][2]):
operation.maxWindow()
operation.order(actual_code, set_stocks_info[row][3], set_stocks_info[row][4])
dt = datetime.datetime.now()
is_ordered[row] = 0
operation.refresh()
cur_position = operation.getPosition()
is_dealt[row] = operation.getDeal(actual_code, pre_position, cur_position)
consignation_info.append(
(dt.strftime('%x'), dt.strftime('%X'), actual_code,
actual_name, set_stocks_info[row][3],
actual_price, set_stocks_info[row][4], '已委托', is_dealt[row]))
pre_position = cur_position
if count % 200 == 0:
operation.refresh()
time.sleep(3)
count += 1

except:
    tkinter.messagebox.showerror('錯誤', '請先打開“同花順雙向委托界面”后在打開自動交易系統(tǒng)!')
    sys.exit()

class StockGui:
global is_monitor
def init(self):
self.window = Tk()
self.window.title("自動化交易系統(tǒng)-同花順")
# 左上角圖標(biāo)
self.window.iconbitmap('e:\ico.ico')
self.window.resizable(0, 0)
frame1 = Frame(self.window)
frame1.pack(padx=10, pady=10)
Label(frame1, text="股票代碼", width=8, justify=CENTER).grid(
row=1, column=1, padx=5, pady=5)
Label(frame1, text="股票名稱", width=8, justify=CENTER).grid(
row=1, column=2, padx=5, pady=5)
Label(frame1, text="實時價格", width=8, justify=CENTER).grid(
row=1, column=3, padx=5, pady=5)
Label(frame1, text="關(guān)系", width=4, justify=CENTER).grid(
row=1, column=4, padx=5, pady=5)
Label(frame1, text="設(shè)定價格", width=8, justify=CENTER).grid(
row=1, column=5, padx=5, pady=5)
Label(frame1, text="方向", width=4, justify=CENTER).grid(
row=1, column=6, padx=5, pady=5)
Label(frame1, text="數(shù)量", width=8, justify=CENTER).grid(
row=1, column=7, padx=5, pady=5)
Label(frame1, text="時間可選", width=8, justify=CENTER).grid(
row=1, column=8, padx=5, pady=5)
Label(frame1, text="委托", width=6, justify=CENTER).grid(
row=1, column=9, padx=5, pady=5)
Label(frame1, text="成交", width=6, justify=CENTER).grid(
row=1, column=10, padx=5, pady=5)
self.rows = NUM_OF_STOCKS
self.cols = 10
self.variable = []
for row in range(self.rows):
self.variable.append([])
for col in range(self.cols):
self.variable[row].append(StringVar())
for row in range(self.rows):
Entry(frame1, textvariable=self.variable[row][0],
width=8).grid(row=row + 2, column=1, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][1], state=DISABLED,
width=8).grid(row=row + 2, column=2, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][2], state=DISABLED, justify=RIGHT,
width=8).grid(row=row + 2, column=3, padx=5, pady=5)
Combobox(frame1, values=('<', '>'), textvariable=self.variable[row][3],
width=2).grid(row=row + 2, column=4, padx=5, pady=5)
Spinbox(frame1, from_=0, to=999, textvariable=self.variable[row][4], justify=RIGHT,
increment=0.01, width=6).grid(row=row + 2, column=5, padx=5, pady=5)
Combobox(frame1, values=('B', 'S'), textvariable=self.variable[row][5],
width=2).grid(row=row + 2, column=6, padx=5, pady=5)
Spinbox(frame1, from_=0, to=10000, textvariable=self.variable[row][6], justify=RIGHT,
increment=100, width=6).grid(row=row + 2, column=7, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][7],
width=8).grid(row=row + 2, column=8, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][8], state=DISABLED, justify=CENTER,
width=6).grid(row=row + 2, column=9, padx=5, pady=5)
Entry(frame1, textvariable=self.variable[row][9], state=DISABLED, justify=RIGHT,
width=6).grid(row=row + 2, column=10, padx=5, pady=5)

    frame3 = Frame(self.window)
    frame3.pack(padx=10, pady=10)
     # 創(chuàng)建菜單功能
    self.menuBar = Menu(self.window)
    self.window.config(menu=self.menuBar)
    # tearoff=0 代表將菜單項最上面的一條虛線去掉,默認(rèn)是存在的
    self.fileMenu = Menu(self.menuBar,tearoff=0)
    # 創(chuàng)建一個名為“幫助”的菜單項
    self.menuBar.add_cascade(label="幫助",menu=self.fileMenu)
    # 在“幫助”項下添加一個名為“關(guān)于”的選項
    self.fileMenu.add_command(label="關(guān)于",command =self.about)
    # 增加一條橫線
    self.fileMenu.add_separator()
    # 在“幫助”項下添加一個名為“退出”的選項,并綁定執(zhí)行函數(shù)
    self.fileMenu.add_command(label="退出",command=self.close)
    # 增加第二個導(dǎo)航欄
    # self.helpMenu = Menu(self.menuBar,tearoff=0)
    # self.menuBar.add_cascade(label="Help", menu=self.helpMenu)
    # self.helpMenu.add_command(label="About")
    self.start_bt = Button(frame3, text="開始", command=self.start)
    self.start_bt.pack(side=LEFT)
    self.set_bt = Button(frame3, text='重置買賣', command=self.setFlags)
    self.set_bt.pack(side=LEFT)
    Button(frame3, text="歷史記錄", command=self.displayHisRecords).pack(side=LEFT)
    Button(frame3, text='保存', command=self.save).pack(side=LEFT)
    self.load_bt = Button(frame3, text='載入', command=self.load)
    self.load_bt.pack(side=LEFT)
    self.window.protocol(name="WM_DELETE_WINDOW", func=self.close)
    self.window.after(100, self.updateControls)
    self.window.mainloop()

def displayHisRecords(self):
    """
    顯示歷史信息
    """
    global consignation_info
    tp = Toplevel()
    tp.title('歷史記錄')
    tp.iconbitmap('e:\ico.ico')
    tp.resizable(0, 1)
    scrollbar = Scrollbar(tp)
    scrollbar.pack(side=RIGHT, fill=Y)
    col_name = ['日期', '時間', '證券代碼', '證券名稱', '方向', '價格', '數(shù)量', '委托', '成交']
    tree = Treeview(
        tp, show='headings', columns=col_name, height=30, yscrollcommand=scrollbar.set)
    tree.pack(expand=1, fill=Y)
    scrollbar.config(command=tree.yview)
    for name in col_name:
        tree.heading(name, text=name)
        tree.column(name, width=70, anchor=CENTER)

    for msg in consignation_info:
        tree.insert('', 0, values=msg)
def save(self):
    """
    保存設(shè)置
    """
    global set_stocks_info, consignation_info
    self.getItems()
    with open('stockInfo.dat', 'wb') as fp:
        pickle.dump(set_stocks_info, fp)
        pickle.dump(consignation_info, fp)
def load(self):
    """
    載入設(shè)置
    """
    global set_stocks_info, consignation_info
    try:
        with open('stockInfo.dat', 'rb') as fp:
            set_stocks_info = pickle.load(fp)
            consignation_info = pickle.load(fp)
        for row in range(self.rows):
            for col in range(self.cols):
                if col == 0:
                    self.variable[row][col].set(set_stocks_info[row][0])
                elif col == 3:
                    self.variable[row][col].set(set_stocks_info[row][1])
                elif col == 4:
                    self.variable[row][col].set(set_stocks_info[row][2])
                elif col == 5:
                    self.variable[row][col].set(set_stocks_info[row][3])
                elif col == 6:
                    self.variable[row][col].set(set_stocks_info[row][4])
                elif col == 7:
                    temp = set_stocks_info[row][5].strftime('%X')
                    if temp == '01:00:00':
                        self.variable[row][col].set('')
                    else:
                        self.variable[row][col].set(temp)
    except Exception :
        tkinter.messagebox.showerror('錯誤', "沒有找到配置保存文件,請先進行股票買賣配置信息保存!")
def setFlags(self):
    """
    重置買賣標(biāo)志
    """
    global is_start, is_ordered
    if is_start is False:
        is_ordered = [1] * NUM_OF_STOCKS
        tkinter.messagebox.showinfo('重置成功', "重置成功!")
def updateControls(self):
    """
    實時股票名稱、價格、狀態(tài)信息
    """
    global actual_stocks_info, is_start
    if is_start:
        for row, (actual_code, actual_name, actual_price) in enumerate(actual_stocks_info):
            if actual_code:
                self.variable[row][1].set(actual_name)
                self.variable[row][2].set(str(actual_price))
                if is_ordered[row] == 1:
                    self.variable[row][8].set('監(jiān)控中')
                elif is_ordered[row] == 0:
                    self.variable[row][8].set('已委托')
                self.variable[row][9].set(str(is_dealt[row]))
            else:
                self.variable[row][1].set('')
                self.variable[row][2].set('')
                self.variable[row][8].set('')
                self.variable[row][9].set('')
    self.window.after(3000, self.updateControls)
@staticmethod
def __pickCodeFromItems(items_info):
    """
    提取股票代碼
    :param items_info: UI下各項輸入信息
    :return:股票代碼列表
    """
    stock_codes = []
    for item in items_info:
        stock_codes.append(item[0])
    return stock_codes

def start(self):
    """
    啟動停止
    """
    global is_start, stock_codes, set_stocks_info
    if is_start is False:
        is_start = True
    else:
        is_start = False

    if is_start:
        self.getItems()
        stock_codes = self.__pickCodeFromItems(set_stocks_info)
        self.start_bt['text'] = '停止'
        self.set_bt['state'] = DISABLED
        self.load_bt['state'] = DISABLED
        tkinter.messagebox.showinfo('成功','啟動成功!')
    else:
        self.start_bt['text'] = '開始'
        self.set_bt['state'] = NORMAL
        self.load_bt['state'] = NORMAL
def about(self):
    tkinter.messagebox.showinfo("關(guān)于",'\r此系統(tǒng)僅適應(yīng)于同花順網(wǎng)上交易5.0,使用時請先登陸同花順網(wǎng)上交易系統(tǒng)并切換到“同花順雙向委托界面”。\r 版本號:v 1.0.0 \r 作者:水域\r 發(fā)布日期:2017.01.11')
def close(self):
    """
    關(guān)閉程序時,停止monitor線程
    """
    global is_monitor
    is_monitor = False
    self.window.quit()

def getItems(self):
    """
    獲取UI上用戶輸入的各項數(shù)據(jù),
    """
    global set_stocks_info
    set_stocks_info = []
    # 獲取買賣價格數(shù)量輸入項等
    for row in range(self.rows):
        set_stocks_info.append([])
        for col in range(self.cols):
            temp = self.variable[row][col].get().strip()
            if col == 0:
                if len(temp) == 6 and temp.isdigit():  # 判斷股票代碼是否為6位數(shù)
                    set_stocks_info[row].append(temp)
                else:
                    set_stocks_info[row].append('')
            elif col == 3:
                if temp in ('>', '<'):
                    set_stocks_info[row].append(temp)
                else:
                    set_stocks_info[row].append('')
            elif col == 4:
                try:
                    price = float(temp)
                    if price > 0:
                        set_stocks_info[row].append(price)  # 把價格轉(zhuǎn)為數(shù)字
                    else:
                        set_stocks_info[row].append(0)
                except ValueError:
                    set_stocks_info[row].append(0)
            elif col == 5:
                if temp in ('B', 'S'):
                    set_stocks_info[row].append(temp)
                else:
                    set_stocks_info[row].append('')
            elif col == 6:
                if temp.isdigit() and int(temp) >= 0:
                    set_stocks_info[row].append(str(int(temp) // 100 * 100))
                else:
                    set_stocks_info[row].append('')
            elif col == 7:
                try:
                    set_stocks_info[row].append(datetime.datetime.strptime(temp, '%H:%M:%S').time())
                except ValueError:
                    set_stocks_info[row].append(datetime.datetime.strptime('1:00:00', '%H:%M:%S').time())

if name == 'main':
# StockGui()
t1 = threading.Thread(target=StockGui)
t1.start()
t2 = threading.Thread(target=monitor)
t2.start()

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Gird布局 一、概述 網(wǎng)格布局(Grid)是最強大的 CSS 布局方案。 它將網(wǎng)頁劃分成一個個網(wǎng)格,可以任意組合...
    東東丶醬閱讀 812評論 0 1
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,890評論 0 13
  • 網(wǎng)格線(Grid Line) 構(gòu)成網(wǎng)格結(jié)構(gòu)的分界線。它們既可以是垂直的(“列網(wǎng)格線(column grid lin...
    晚溪呀閱讀 1,287評論 0 0
  • Grid布局 基本概念 1、項目和容器 設(shè)置了 display: gird 的元素,稱為Grid Containe...
    Dec停云閱讀 140評論 0 0
  • 庫和表的管理 常見類型 常見約束 標(biāo)識列
    CodeDragon閱讀 328評論 0 0

友情鏈接更多精彩內(nèi)容