"""
|
GUI管理
|
"""
|
from tkinter import *
|
from tkinter.messagebox import *
|
|
import numpy
|
import tkintertable
|
|
import win32gui
|
|
import constant
|
import data_export_util
|
import multiprocessing
|
|
import log
|
from db import mysql_data, redis_manager
|
import server
|
import settings
|
from juejin import JueJinManager
|
from l2_code_operate import L2CodeOperate
|
from trade import l2_trade_util
|
from trade.l2_trade_factor import L2TradeFactorUtil
|
from ocr import ocr_server
|
from third_data import data_server, kpl_data_manager, kpl_util
|
|
from server import *
|
import l2.l2_data_util
|
|
# 读取server进程的消息
|
from trade.trade_data_manager import CodeActualPriceProcessor
|
from ui.my_widget import FlatButton
|
|
|
def __read_server_pipe(pipe):
|
while True:
|
value = pipe.recv()
|
if value is not None:
|
value = json.loads(value)
|
if value.get("type") == "clear_l2":
|
code = value["data"]["code"]
|
print("清除l2数据", code)
|
if len(code) != 6:
|
continue
|
l2_data_manager.clear_l2_data(code)
|
# 删除level2的数据
|
if l2.l2_data_util.local_today_datas and code in l2.l2_data_util.local_today_datas:
|
l2.l2_data_util.local_today_datas.pop(code)
|
if l2.l2_data_util.local_latest_datas and code in l2.l2_data_util.local_latest_datas:
|
l2.l2_data_util.local_latest_datas.pop(code)
|
|
time.sleep(0.1)
|
|
|
def createServer(pipe_juejin, pipe_gui):
|
print("create SocketServer")
|
# 初始化参数
|
global_data_loader.init()
|
|
t1 = threading.Thread(target=lambda: __read_server_pipe(pipe_gui))
|
# 后台运行
|
t1.setDaemon(True)
|
t1.start()
|
|
t1 = threading.Thread(target=createDataServer)
|
# 后台运行
|
t1.setDaemon(True)
|
t1.start()
|
|
|
|
laddr = "", 9001
|
tcpserver = MyThreadingTCPServer(laddr, MyBaseRequestHandle, pipe_juejin=pipe_juejin) # 注意:参数是MyBaseRequestHandle
|
# tcpserver.handle_request() # 只接受一个客户端连接
|
tcpserver.serve_forever() # 永久循环执行,可以接受多个客户端连接
|
|
|
def createOCRServer():
|
print("create OCRServer")
|
tcpserver = ocr_server.run("", 9002)
|
tcpserver.serve_forever()
|
|
def createDataServer():
|
print("create OCRServer")
|
tcpserver = data_server.run("", 9004)
|
tcpserver.serve_forever()
|
|
def startJueJin(pipe):
|
juejin.JueJinManager(pipe).start()
|
|
|
class GUI:
|
|
def __init__(self):
|
p1, p2 = multiprocessing.Pipe()
|
gs_gui_pipe, gs_server_pipe = multiprocessing.Pipe()
|
|
self.serverProcess = multiprocessing.Process(target=createServer, args=(p1, gs_server_pipe,))
|
self.jueJinProcess = multiprocessing.Process(target=startJueJin, args=(p2,))
|
self.ocrServerProcess = multiprocessing.Process(target=createOCRServer)
|
|
|
self.p1 = p1
|
self.p2 = p2
|
self.gs_gui_pipe = gs_gui_pipe
|
self.thsBuy1VolumnManager = THSBuy1VolumnManager()
|
self.codeActualPriceProcessor = CodeActualPriceProcessor()
|
# L2显示
|
self.l2_codes = {}
|
self.selected_client = {}
|
# 获取l2的客户端列表
|
clients = authority.get_l2_clients()
|
for client_id in clients:
|
self.l2_codes[client_id] = []
|
for i in range(0, constant.L2_CODE_COUNT_PER_DEVICE):
|
code = gpcode_manager.get_listen_code_by_pos(client_id, i)
|
self.l2_codes[client_id].append(code)
|
|
# 读取server进程的消息
|
def __read_gui_server_pipe(self, pipe):
|
while True:
|
value = pipe.recv()
|
if value is not None:
|
value = json.loads(value)
|
if value.get("type") == "l2_data_notify":
|
code = value["data"]["code"]
|
count = value["data"]["count"]
|
print("l2数据通知:{}-{}", code, count)
|
|
time.sleep(0.1)
|
|
def run(self):
|
# TODO
|
self.jueJinProcess.start()
|
self.serverProcess.start()
|
self.ocrServerProcess.start()
|
|
L2CodeOperate.get_instance()
|
# 客户端队列操作
|
process = multiprocessing.Process(target=L2CodeOperate.run())
|
process.start()
|
|
# 客户端server连接
|
t1 = threading.Thread(target=lambda: server.test_client_server())
|
# 后台运行
|
t1.setDaemon(True)
|
t1.start()
|
|
t1 = threading.Thread(target=lambda: self.__read_gui_server_pipe(self.gs_gui_pipe))
|
# 后台运行
|
t1.setDaemon(True)
|
t1.start()
|
|
self.create_gui()
|
|
def _draw_check(self, root):
|
|
def _set_error_color(text, line, content):
|
for i in range(0, len(content)):
|
text.tag_add('error', "{}.{}".format(line, i))
|
|
def click():
|
text.delete('1.0', END)
|
|
# 验证redis
|
try:
|
redis = redis_manager.RedisManager().getRedis()
|
redis.set("test", "1")
|
redis.delete("test")
|
text.insert(END, "redis连接成功!\n")
|
except:
|
error = "redis连接失败...\n"
|
text.insert(END, error)
|
_set_error_color(text, 1, error)
|
# 验证mongodb
|
try:
|
counts = mysql_data.Mysqldb().select_one("select count(*) from clients")
|
if counts[0] < 1:
|
raise Exception("")
|
text.insert(END, "mysql连接成功!\n")
|
except:
|
error = "mysql连接失败...\n"
|
text.insert(END, error)
|
_set_error_color(text, 2, error)
|
pass
|
|
try:
|
trade_gui.THSGuiTrade.checkEnv()
|
text.insert(END, "交易环境检测通过!\n")
|
except Exception as e:
|
error = "交易环境异常-{}...\n".format(str(e))
|
text.insert(END, error)
|
_set_error_color(text, 3, error)
|
pass
|
jurjin_win = 0
|
hWndList = []
|
win32gui.EnumWindows(lambda hWnd, param: param.append(hWnd), hWndList)
|
for hwnd in hWndList:
|
title = win32gui.GetWindowText(hwnd)
|
if title.find("掘金") > -1:
|
print(title)
|
jurjin_win = hwnd
|
break
|
if jurjin_win > 0:
|
text.insert(END, "交易环境-掘金客户端已开启!\n")
|
else:
|
error = "交易环境异常-掘金客户端未开启\n"
|
text.insert(END, error)
|
_set_error_color(text, 4, error)
|
|
text.tag_config('error', foreground='red')
|
|
# 设置掘金信息
|
width = 300
|
height = 150
|
frame = Frame(root, {"height": height, "width": width, "bg": "#DDDDDD"})
|
|
text = Text(frame, height=100, undo=True)
|
text.place(x=0, y=40)
|
|
btn = FlatButton(frame, text="运行环境检测", command=click)
|
btn.place(x=5, y=5)
|
|
frame.grid(row=1, column=2)
|
|
# 绘制开盘前的数据准备情况
|
def __draw_pre_data_check(self, frame):
|
def refresh_close_price_data():
|
redis = redis_manager.RedisManager(0).getRedis()
|
count = len(redis.keys("price-pre-*"))
|
sv_num.set("获取到收盘价数量:{}".format(count))
|
|
def re_get_close_price():
|
juejin.re_set_price_pres(gpcode_manager.get_gp_list())
|
|
def get_limit_up_codes_win():
|
width = 500
|
height = 800
|
win = Tk()
|
win.title("今日涨停")
|
win.resizable(height=False, width=False)
|
|
limit_up_datas = {}
|
limit_up_datas["row{}".format(0)] = {'代码': '', '首次涨停时间': '', '现价': '', '涨幅': '', '涨停封单额': ''}
|
|
cl = Label(win, text="更新时间:", bg="#DDDDDD", fg="#666666")
|
cl.place(x=10, y=10)
|
|
limit_up_datas_time = StringVar(value="未知")
|
cl = Label(win, textvariable=limit_up_datas_time, bg="#DDDDDD", fg="#666666")
|
cl.place(x=100, y=10)
|
|
table_height = height - 100
|
table_width = width - 20
|
|
table_frame = Frame(win, {"height": table_height, "width": table_width, "bg": "#DDDDDD"})
|
table_frame.place(x=10, y=45)
|
table_limit_up = tkintertable.TableCanvas(table_frame, data=limit_up_datas, read_only=True,
|
width=table_width,
|
height=table_height, thefont=('微软雅黑', 10), cellwidth=90,
|
rowheaderwidth=20)
|
table_limit_up.show()
|
|
# 获取数据
|
time_str, datas = gpcode_manager.get_limit_up_list()
|
limit_up_datas_time.set(time_str)
|
# 删除所有的行
|
# table_limit_up.model.deleteRows()
|
# 增加数据
|
index = 0
|
for data in datas:
|
data = json.loads(data)
|
table_limit_up.model.addRow()
|
table_limit_up.model.setValueAt(data["code"], index, 0)
|
table_limit_up.model.setValueAt(data["time"], index, 1)
|
table_limit_up.model.setValueAt(float(data["price"]), index, 2)
|
table_limit_up.model.setValueAt(float(data["limitUpPercent"]), index, 3)
|
table_limit_up.model.setValueAt(
|
"{}{}".format(float(data["limitMoney"]), ("亿" if data["limitMoneyUnit"] == 0 else "万")), index, 4)
|
index += 1
|
table_limit_up.redraw()
|
|
win.geometry("{}x{}".format(width, height))
|
win.mainloop()
|
|
# 绘制代码交易窗口分配
|
def refresh_trade_buy_win_data():
|
code_wins = trade_gui.THSBuyWinManagerNew.get_distributed_code_wins()
|
# 获取代码涨幅
|
codeActualPriceProcessor = trade_data_manager.CodeActualPriceProcessor()
|
datas = []
|
for data in code_wins:
|
rate = codeActualPriceProcessor.get_current_rate(data[0])
|
datas.append((data[0], rate, data[1]))
|
datas.sort(key=lambda tup: tup[1] if tup[1] is not None else 1)
|
datas.reverse()
|
index = 0
|
table.model.deleteRows()
|
for data in datas:
|
table.model.addRow()
|
table.model.setValueAt(data[0], index, 0)
|
table.model.setValueAt(f"{data[1]}%", index, 1)
|
table.model.setValueAt(data[2], index, 2)
|
# table.model.setValueAt(data["apply_time"], index, 2)
|
index += 1
|
table.redraw()
|
# 刷新开盘啦数据
|
def refresh_kpl_data():
|
kpl_data_manager.KPLDataManager().get_data(kpl_util.KPLDataType.LIMIT_UP)
|
kpl_data_manager.KPLDataManager().get_data(kpl_util.KPLDataType.OPEN_LIMIT_UP)
|
kpl_data_manager.KPLDataManager().get_data(kpl_util.KPLDataType.BEST_FENG_KOU)
|
kpl_data_manager.KPLDataManager().get_data(kpl_util.KPLDataType.FENG_KOU)
|
kpl_data_manager.KPLDataManager().get_data(kpl_util.KPLDataType.FENG_XIANG)
|
|
|
start_y = 225
|
btn = FlatButton(frame, text="刷新收盘价", command=refresh_close_price_data)
|
btn.place(x=5, y=start_y)
|
|
sv_num = StringVar(value="获取到收盘价数量:未知")
|
cl = Label(frame, textvariable=sv_num, bg="#DDDDDD", fg="#666666")
|
cl.place(x=5, y=start_y + 30)
|
|
btn = FlatButton(frame, text="重新获取收盘价", command=re_get_close_price)
|
btn.place(x=80, y=start_y)
|
kpl_data = Label(text="涨停:\n炸板:\n最强:\n风向:\n风口:",bg="#DDDDDD",fg="#666666")
|
kpl_data.place(x=190, y=start_y)
|
|
trade_win_datas = []
|
# draw_trade_buy_win(360, 140)
|
table_width = 300
|
table_height = 95
|
_frame = Frame(frame, {"height": table_height, "width": table_width, "bg": "#DDDDDD"})
|
|
table = tkintertable.TableCanvas(_frame, data={"row0": {'代码': '', '涨幅': '', '窗口句柄': ''}}, read_only=True,
|
width=table_width, height=table_height, thefont=('微软雅黑', 9), cellwidth=100,
|
rowheaderwidth=20)
|
table.show()
|
_frame.place(x=450, y=start_y)
|
refresh_trade_buy_win_data()
|
refresh_close_price_data()
|
|
btn = FlatButton(frame, text="刷新", command=refresh_trade_buy_win_data)
|
btn.place(x=450 - 35, y=start_y)
|
|
def re_distribute_buy_win():
|
try:
|
if tool.trade_time_sub(tool.get_now_time_str(), "09:30:00") > 0:
|
raise Exception("只能9:30之前重新分配窗口")
|
datas = JueJinManager.get_codes_limit_rate(gpcode_manager.get_gp_list())
|
matrix = numpy.array(datas)
|
codes = matrix[:, 0].tolist()
|
trade_gui.re_distribute_buy_win(codes)
|
refresh_trade_buy_win_data()
|
showinfo("提示", "分配完成")
|
except Exception as e:
|
showerror("分配出错", str(e))
|
|
btn = FlatButton(frame, text="重新分配窗口", command=re_distribute_buy_win)
|
btn.place(x=450 - 83, y=start_y + 30)
|
|
# 绘制交易状态
|
def __draw_trade_state(self, frame):
|
def refresh_data():
|
normal = True
|
if l2_code_operate.L2CodeOperate.is_read_queue_valid():
|
cl_queue.configure(text="正常", foreground="#008000")
|
else:
|
cl_queue.configure(text="异常", foreground="#FF7F27")
|
normal = False
|
try:
|
trade_gui.THSGuiTrade.checkEnv()
|
cancel_win_num = trade_gui.THSGuiTrade.getCancelBuyWins()
|
cl_win.configure(text=f"正常({len(cancel_win_num)})", foreground="#008000")
|
except Exception as e:
|
normal = False
|
cl_win.configure(text="异常:{}".format(str(e)), foreground="#FF7F27")
|
|
try:
|
juejin_length = JueJinManager.get_listen_codes_lenth()
|
codes_length = len(gpcode_manager.get_gp_list())
|
cl_codes.configure(text="{}/{}".format(juejin_length, codes_length), foreground="#008000")
|
except Exception as e:
|
pass
|
|
# 获取板块状态
|
try:
|
ths_dead = client_manager.getTHSState(7)
|
if ths_dead is None:
|
cl_block.configure(text="离线", foreground="#FF7F27")
|
elif ths_dead:
|
normal = False
|
cl_block.configure(text="离线", foreground="#FF7F27")
|
else:
|
cl_block.configure(text="在线", foreground="#008000")
|
except:
|
pass
|
|
try:
|
codes = self.thsBuy1VolumnManager.get_current_codes()
|
count = 0
|
if codes:
|
count = len(codes)
|
if count < 1:
|
normal = False
|
cl_buy_1.configure(text="{}".format(count), foreground="#FF7F27")
|
else:
|
cl_buy_1.configure(text="{}".format(count), foreground="#008000")
|
except:
|
pass
|
|
try:
|
count = self.codeActualPriceProcessor.get_current_price_codes_count()
|
if count is None or int(count) < 1:
|
normal = False
|
cl_price_count.configure(
|
text="{}".format(count),
|
foreground="#FF7F27")
|
else:
|
cl_price_count.configure(
|
text="{}".format(count),
|
foreground="#008000")
|
except:
|
pass
|
|
# 获取有效的L2客户端数量
|
l2_client_count = client_manager.getValidL2Clients()
|
if len(l2_client_count) < 6:
|
normal = False
|
|
# 状态有问题,需要报警
|
if not normal:
|
alert_util.alarm()
|
|
def update_data():
|
while True:
|
# 刷新数据
|
try:
|
if auo_refresh.get() > 0:
|
refresh_data()
|
except:
|
pass
|
time.sleep(2)
|
|
start_y = 285
|
|
btn = FlatButton(frame, text="刷新状态", command=refresh_data)
|
btn.place(x=10, y=start_y)
|
|
auo_refresh = IntVar()
|
ch1 = Checkbutton(frame, text='自动刷新', variable=auo_refresh, onvalue=1, offvalue=0, background="#DDDDDD",
|
activebackground="#DDDDDD")
|
# 默认自动刷新
|
auo_refresh.set(1)
|
ch1.place(x=100, y=start_y)
|
|
y_ = start_y + 30
|
cl = Label(frame, text="操作队列状态:", bg="#DDDDDD")
|
cl.place(x=10, y=y_)
|
cl_queue = Label(frame, text="未知", bg="#DDDDDD")
|
cl_queue.place(x=100, y=y_)
|
|
cl = Label(frame, text="交易窗口状态:", bg="#DDDDDD")
|
cl.place(x=170, y=y_)
|
cl_win = Label(frame, text="未知", bg="#DDDDDD")
|
cl_win.place(x=270, y=y_)
|
|
cl = Label(frame, text="板块状态:", bg="#DDDDDD")
|
cl.place(x=320, y=y_)
|
cl_block = Label(frame, text="未知", bg="#DDDDDD")
|
cl_block.place(x=380, y=y_)
|
|
cl = Label(frame, text="掘金代码回调数量:", bg="#DDDDDD")
|
cl.place(x=300, y=y_ + 20)
|
cl_codes = Label(frame, text="未知", bg="#DDDDDD")
|
cl_codes.place(x=410, y=y_ + 20)
|
|
cl = Label(frame, text="买1代码数量:", bg="#DDDDDD")
|
cl.place(x=10, y=y_ + 20)
|
cl_buy_1 = Label(frame, text="未知", bg="#DDDDDD")
|
cl_buy_1.place(x=10 + 90, y=y_ + 20)
|
|
cl = Label(frame, text="现价代码数量:", bg="#DDDDDD")
|
cl.place(x=170, y=y_ + 20)
|
cl_price_count = Label(frame, text="未知", bg="#DDDDDD")
|
cl_price_count.place(x=170 + 100, y=y_ + 20)
|
|
refresh_data()
|
# 添加更新线程
|
t1 = threading.Thread(target=lambda: update_data())
|
# 后台运行
|
t1.setDaemon(True)
|
t1.start()
|
|
# 绘制l2数据状态
|
def __draw_l2_state(self, root):
|
def update_data():
|
while True:
|
# 刷新数据
|
try:
|
if auo_refresh.get() > 0:
|
refresh_data()
|
except:
|
pass
|
time.sleep(1)
|
|
def refresh_data():
|
for client_id in code_sv_map:
|
ip = client_manager.getActiveClientIP(client_id)
|
ths_dead = client_manager.getTHSState(client_id)
|
if ip is not None and len(ip) > 0:
|
if ths_dead:
|
client_state[client_id].configure(text="(在线:{})".format(ip), foreground="#FF7F27")
|
else:
|
client_state[client_id].configure(text="(在线:{})".format(ip), foreground="#008000")
|
else:
|
client_state[client_id].configure(text="(离线:未知IP)", foreground="#999999")
|
|
for i in range(0, constant.L2_CODE_COUNT_PER_DEVICE):
|
code = gpcode_manager.get_listen_code_by_pos(client_id, i)
|
data_count = l2_data_util.get_l2_latest_data_number(code)
|
if data_count is None:
|
data_count = 0
|
if code is not None and len(code) > 0:
|
code_sv_map[client_id][i].set(code + "({})".format(data_count))
|
else:
|
code_sv_map[client_id][i].set("")
|
if data_count > 0:
|
code_labels[client_id][i].configure(foreground="#FF0000")
|
|
else:
|
code_labels[client_id][i].configure(foreground="#999999")
|
|
def check(client):
|
msg_list = []
|
try:
|
result = get_client_env_state(client)
|
if result["ths_l2_win"]:
|
msg_list.append(("同花顺L2屏正常!", 0))
|
else:
|
msg_list.append(("同花顺L2屏未打开...", 1))
|
if result["ths_fp_1"]:
|
msg_list.append(("同花顺副屏1正常!", 0))
|
else:
|
msg_list.append(("同花顺副屏1未打开...", 1))
|
|
if result["ths_fp_2"]:
|
msg_list.append(("同花顺副屏2正常!", 0))
|
else:
|
msg_list.append(("同花顺副屏2未打开...", 1))
|
|
if result["ths_trade_success"]:
|
msg_list.append(("交易成功页面正常!", 0))
|
else:
|
msg_list.append(("交易成功页面未打开...", 1))
|
|
if result["l2_channel_invalid_count"] <= 0:
|
msg_list.append(("L2监控线程正常数:{} 异常数:{}...".format(result["l2_channel_valid_count"],
|
result["l2_channel_invalid_count"]), 0))
|
else:
|
msg_list.append(("L2监控线程正常数:{} 异常数:{}!".format(result["l2_channel_valid_count"],
|
result["l2_channel_invalid_count"]), 1))
|
|
if result["limitUp"]:
|
msg_list.append(("涨停监控线程正常!", 0))
|
else:
|
msg_list.append(("涨停监控线程异常...", 1))
|
|
if result["tradeSuccess"]:
|
msg_list.append(("当日成交监控线程正常!", 0))
|
else:
|
msg_list.append(("当日成交监控线程异常...", 1))
|
|
except Exception as e:
|
msg_list.append((str(e), 1))
|
|
def repair():
|
try:
|
server.repair_client_env(client)
|
showinfo("提示", "修复完成")
|
except Exception as e:
|
showerror("修复出错", str(e))
|
|
# 创建界面
|
win = Tk()
|
win.title("检测结果")
|
win.resizable(height=False, width=False)
|
text = Text(win, height=100, undo=True)
|
text.place(x=0, y=30)
|
btn = FlatButton(win, text="一键修复", command=repair)
|
btn.place(x=0, y=0)
|
|
line = 0
|
for msg in msg_list:
|
line += 1
|
if msg[1] == 0:
|
text.insert(END, "{}\n".format(msg[0]))
|
else:
|
text.insert(END, "{}\n".format(msg[0]))
|
for i in range(0, len(msg[0])):
|
text.tag_add('error', "{}.{}".format(line, i))
|
|
text.tag_config('error', foreground='red')
|
|
win.geometry("300x300")
|
win.mainloop()
|
|
def init():
|
juejin.everyday_init()
|
|
def set_accept_l2():
|
settings.set_accept_l2(accept_l2.get())
|
|
def pop_menu(event):
|
self.selected_client = event.widget["command"]
|
menu.post(event.x_root, event.y_root)
|
|
def ths_test_speed():
|
if self.selected_client is None:
|
showwarning("警告", "未选中客户端")
|
return
|
try:
|
server.repair_ths_main_site(self.selected_client)
|
showinfo("提示", "同花顺测速完成")
|
except Exception as e:
|
showerror("错误", str(e))
|
|
def check_env():
|
if self.selected_client is None:
|
showwarning("警告", "未选中客户端")
|
return
|
check(self.selected_client)
|
|
width = 800
|
height = 360
|
frame = Frame(root, {"height": height, "width": width, "bg": "#DDDDDD"})
|
trade_info= ""
|
for_color = "#008000"
|
if constant.TEST:
|
trade_info += "测试环境"
|
for_color = "#FF7F27"
|
else:
|
trade_info += "正式环境"
|
trade_info += " "
|
if constant.TRADE_ENABLE:
|
trade_info += "初始允许交易"
|
else:
|
trade_info += "初始禁止交易"
|
for_color = "#FF7F27"
|
|
cl = Label(frame, text=f"{trade_info}", bg="#DDDDDD",foreground=f"{for_color}")
|
cl.place(x=5, y=5)
|
|
accept_l2 = IntVar()
|
ch_accept_l2 = Checkbutton(frame, text='接受l2数据', variable=accept_l2, onvalue=1, offvalue=0,
|
background="#DDDDDD", activebackground="#DDDDDD", command=set_accept_l2)
|
ch_accept_l2.place(x=width - 350, y=5)
|
if settings.is_accept_l2_data():
|
accept_l2.set(1)
|
else:
|
accept_l2.set(0)
|
|
btn = FlatButton(frame, text="每日初始化", command=init)
|
btn.place(x=width - 250, y=5)
|
|
btn = FlatButton(frame, text="刷新数据", command=refresh_data)
|
btn.place(x=width - 150, y=5)
|
auo_refresh = IntVar()
|
ch1 = Checkbutton(frame, text='自动刷新', variable=auo_refresh, onvalue=1, offvalue=0, background="#DDDDDD",
|
activebackground="#DDDDDD")
|
ch1.place(x=width - 80, y=5)
|
auo_refresh.set(1)
|
|
l2_client_count = 0
|
code_sv_map = {}
|
code_labels = {}
|
client_state = {}
|
|
# 右键菜单
|
menu = Menu(frame,
|
tearoff=False,
|
# bg="black",
|
)
|
menu.add_command(label="环境检测", command=check_env)
|
menu.add_command(label="同花顺测速", command=ths_test_speed)
|
|
device_index =0
|
for key in self.l2_codes:
|
device_index += 1
|
client_lb = Label(frame, text="设备:{} ID:{}".format(device_index,key), background="#DDDDDD")
|
client_lb.place(x=38, y=40 + l2_client_count * 30)
|
btn = FlatButton(frame, text="检测", command=key)
|
btn.bind('<Button-3>', lambda event: pop_menu(event))
|
btn.place(x=5, y=35 + l2_client_count * 30)
|
|
client_state_lb = Label(frame, text="(未知)", padx=0, pady=0, background="#DDDDDD", font=('微软雅黑', 8))
|
client_state_lb.place(x=112, y=40 + l2_client_count * 30)
|
client_state[key] = client_state_lb
|
code_sv_map[key] = []
|
code_labels[key] = []
|
for i in range(0, constant.L2_CODE_COUNT_PER_DEVICE):
|
sv = StringVar(value=self.l2_codes[key][i])
|
code_sv_map[key].append(sv)
|
cframe = Frame(frame, {"height": 23, "width": 80, "bg": "#FFFFFF"})
|
code_label = Label(cframe, textvariable=sv, background="#FFFFFF", foreground="#FF0000")
|
code_labels[key].append(code_label)
|
|
code_label.place(x=0, y=0)
|
cframe.place(x=250 + i * 85, y=40 + l2_client_count * 30)
|
l2_client_count += 1
|
# 添加更新线程
|
t1 = threading.Thread(target=lambda: update_data())
|
# 后台运行
|
t1.setDaemon(True)
|
t1.start()
|
refresh_data()
|
self.__draw_pre_data_check(frame)
|
|
frame.grid(row=0, column=1, padx=5, pady=5, rowspan=2)
|
|
# 绘制交易数据
|
def __draw_trade_data(self, root):
|
def auto_refresh():
|
while True:
|
if auo_refresh.get() > 0:
|
refresh_data()
|
time.sleep(1)
|
|
def refresh_data():
|
money = trade_manager.get_available_money()
|
if money is not None:
|
sv_trade_money.set(money)
|
else:
|
sv_trade_money.set("未知")
|
|
# 获取委托数据
|
datas, time_str = trade_manager.get_trade_delegate_data()
|
# 删除所有的行
|
table_delegate.model.deleteRows()
|
delegate_datas_time.set(time_str)
|
|
# 增加数据
|
index = 0
|
for data in datas:
|
table_delegate.model.addRow()
|
table_delegate.model.setValueAt(data["time"], index, 0)
|
table_delegate.model.setValueAt(data["code"], index, 1)
|
table_delegate.model.setValueAt(data["apply_time"], index, 2)
|
table_delegate.model.setValueAt(data["num"], index, 3)
|
table_delegate.model.setValueAt(data.get("price"), index, 4)
|
table_delegate.model.setValueAt(data.get("trade_price"), index, 5)
|
table_delegate.model.setValueAt(data.get("trade_num"), index, 6)
|
if int(data["type"]) > 0:
|
table_delegate.model.setValueAt("卖出", index, 7)
|
else:
|
table_delegate.model.setValueAt("买入", index, 7)
|
index += 1
|
table_delegate.redraw()
|
|
# 获取所有的数据
|
datas, time_str = trade_manager.get_trade_success_data()
|
trade_datas_time.set(time_str)
|
# 删除所有的行
|
table_trade.model.deleteRows()
|
# 增加数据
|
index = 0
|
for data in datas:
|
table_trade.model.addRow()
|
table_trade.model.setValueAt(data["code"], index, 0)
|
table_trade.model.setValueAt(data["time"], index, 1)
|
table_trade.model.setValueAt(data["num"], index, 2)
|
table_trade.model.setValueAt(data["price"], index, 3)
|
table_trade.model.setValueAt(data["money"], index, 4)
|
table_trade.model.setValueAt(data["trade_num"], index, 5)
|
if int(data["type"]) > 0:
|
table_trade.model.setValueAt("卖出", index, 6)
|
else:
|
table_trade.model.setValueAt("买入", index, 6)
|
index += 1
|
table_trade.redraw()
|
|
pass
|
|
def create_table(_frame, data, cell_width=75):
|
table = tkintertable.TableCanvas(_frame, data=data, read_only=True, width=table_width,
|
height=table_height, thefont=('微软雅黑', 10), cellwidth=cell_width,
|
rowheaderwidth=20)
|
return table
|
|
# 设置掘金信息
|
width = 800
|
height = 280
|
frame = Frame(root, {"height": height, "width": width, "bg": "#DDDDDD"})
|
cl = Label(frame, text="交易数据", bg="#DDDDDD")
|
cl.place(x=5, y=5)
|
|
# ------表头开始------
|
# 获取交易账户可用金额
|
cl = Label(frame, text="交易账户可用资金:", bg="#DDDDDD", fg="#666666")
|
cl.place(x=80, y=5)
|
|
sv_trade_money = StringVar(value="未知")
|
cl = Label(frame, textvariable=sv_trade_money, bg="#DDDDDD", fg="#666666")
|
cl.place(x=190, y=5)
|
|
btn = FlatButton(frame, text="刷新数据", command=refresh_data)
|
btn.place(x=width - 150, y=5)
|
auo_refresh = IntVar()
|
ch1 = Checkbutton(frame, text='自动刷新', variable=auo_refresh, onvalue=1, offvalue=0, background="#DDDDDD",
|
activebackground="#DDDDDD")
|
ch1.place(x=width - 80, y=5)
|
auo_refresh.set(1)
|
# ------表头结束------
|
|
# 委托表格
|
cl = Label(frame, text="今日委托:", bg="#DDDDDD", fg="#666666")
|
cl.place(x=5, y=30)
|
delegate_datas = {}
|
delegate_datas["row{}".format(0)] = {'委托时间': '', '代码': '', '申报时间': '', '委托数量': '', '委托价格': '', '成交均价': '',
|
'成交数量': '',
|
'操作': ''}
|
|
cl = Label(frame, text="更新时间:", bg="#DDDDDD", fg="#666666")
|
cl.place(x=width / 2 - 130, y=30)
|
|
delegate_datas_time = StringVar(value="未知")
|
cl = Label(frame, textvariable=delegate_datas_time, bg="#DDDDDD", fg="#666666")
|
cl.place(x=width / 2 - 70, y=30)
|
|
table_height = 180
|
table_width = width / 2 - 50
|
|
table_frame = Frame(frame, {"height": table_height, "width": table_width, "bg": "#DDDDDD"})
|
table_frame.place(x=5, y=52)
|
table_delegate = create_table(table_frame, data=delegate_datas)
|
table_delegate.show()
|
|
# 成交表格
|
cl = Label(frame, text="今日成交:", bg="#DDDDDD", fg="#666666")
|
cl.place(x=width / 2, y=30)
|
cl = Label(frame, text="更新时间:", bg="#DDDDDD", fg="#666666")
|
cl.place(x=width - 130, y=30)
|
|
trade_datas_time = StringVar(value="10:00:00")
|
cl = Label(frame, textvariable=trade_datas_time, bg="#DDDDDD", fg="#666666")
|
cl.place(x=width - 70, y=30)
|
|
trade_datas = {}
|
trade_datas["row{}".format(0)] = {'证券代码': '', '成交时间': '', '成交数量': '', '成交均价': '', '成交金额': '',
|
'合同编号': '', '操作': ''}
|
|
table_frame = Frame(frame, {"height": table_height, "width": table_width, "bg": "#DDDDDD"})
|
table_frame.place(x=width / 2, y=52)
|
table_trade = create_table(table_frame, trade_datas, 90)
|
table_trade.show()
|
|
frame.grid(row=2, column=1, padx=5, pady=5, rowspan=2)
|
|
# 添加更新线程
|
t1 = threading.Thread(target=lambda: auto_refresh())
|
# 后台运行
|
t1.setDaemon(True)
|
t1.start()
|
|
def __draw_juejin(self, root):
|
def click():
|
account = account_var.get()
|
sid = sid_var.get()
|
token = token_var.get()
|
if len(account.strip()) < 1 or len(sid.strip()) < 1 or len(token.strip()) < 1:
|
showinfo('提示', "数据不完整")
|
return
|
juejin.setAccountInfo(account, sid, token)
|
showinfo('提示', "设置成功")
|
|
# 设置掘金信息
|
frame = Frame(root, {"height": 150, "width": 300, "bg": "#DDDDDD"})
|
left = 10
|
top = 10
|
|
cl = Label(frame, text="账号ID:", bg="#DDDDDD")
|
cl.place(x=left, y=top)
|
account_var = StringVar(value="1233")
|
entry = Entry(frame, textvariable=account_var, width=30)
|
entry.place(x=left + 60, y=top)
|
|
cl = Label(frame, text="策略ID:", bg="#DDDDDD")
|
cl.place(x=left, y=top + 30)
|
sid_var = StringVar(value="1233")
|
entry = Entry(frame, textvariable=sid_var, width=30)
|
entry.place(x=left + 60, y=top + 30)
|
|
token_var = StringVar(value="1233")
|
cl = Label(frame, text="Token:", bg="#DDDDDD")
|
cl.place(x=left, y=top + 60)
|
entry = Entry(frame, textvariable=token_var, width=30)
|
entry.place(x=left + 60, y=top + 60)
|
|
btn = FlatButton(frame, text="设置掘金参数", command=click)
|
btn.place(x=left + 60, y=top + 90)
|
# frame.place(x=260,y=10)
|
frame.grid(row=0, column=2, pady=5, padx=5)
|
|
# 设置参数
|
account, sid, token = juejin.getAccountInfo()
|
account_var.set(account)
|
sid_var.set(sid)
|
token_var.set(token)
|
|
def __draw_test(self, root):
|
def startJueJinGui():
|
if self.jueJinProcess.is_alive():
|
print("已经启动")
|
else:
|
self.jueJinProcess.start()
|
|
def setGPCode(client, position, gpcode):
|
if client is None or len(client) < 1:
|
return
|
if position is None or len(position) < 1:
|
return
|
if gpcode is None or len(gpcode) < 6:
|
return
|
l2_code_operate.L2CodeOperate.setGPCode(client, position, gpcode)
|
|
def resub():
|
self.p1.send("resub")
|
|
def refresh_hwnds():
|
try:
|
trade_gui.THSGuiTrade.checkEnv()
|
trade_gui.THSGuiTrade().refresh_hwnds()
|
showinfo('提示', "刷新成功")
|
except Exception as e:
|
print(e)
|
showwarning('警告', e)
|
|
def export_l2_data(code):
|
if code not in l2.l2_data_util.local_today_datas:
|
l2.l2_data_util.load_l2_data(code)
|
datas = l2.l2_data_util.local_today_datas[code]
|
try:
|
path = data_export_util.export_l2_data(code, datas)
|
showinfo("提示", "导出成功,路径为:" + path)
|
except Exception as e1:
|
showerror("导出失败", str(e1))
|
|
def export_l2_data_origin(code):
|
redis = redis_manager.RedisManager(1).getRedis()
|
keys = redis.keys("big_data-{}-*".format(code))
|
try:
|
for k in keys:
|
datas = redis.get(k)
|
datas = json.loads(datas)
|
_t = k.split("-")[2]
|
k = time.strftime("%Y_%m_%d_%H_%M_%S_", time.localtime(float(_t) / 1000))
|
k = "{}{}".format(k, _t[-3:])
|
data_export_util.export_l2_data_origin(code, datas, k)
|
except Exception as e1:
|
showerror("导出失败", str(e1))
|
|
showinfo("提示", "导出完成")
|
|
def compute_m(code):
|
m, msg = L2TradeFactorUtil.compute_m_value(code)
|
showinfo("提示", "{}".format(m))
|
|
def clear_l2(code):
|
self.gs_gui_pipe.send(json.dumps({"type": "clear_l2", "data": {"code": code}}))
|
pass
|
|
# 禁止代码
|
def cancel_order(code_):
|
try:
|
l2.l2_data_util.load_l2_data(code_, True)
|
l2_data_manager_new.L2TradeDataProcessor.cancel_buy(code_, "手动撤销")
|
showinfo("提示", "撤单成功")
|
except Exception as e:
|
showwarning("提示", "撤单成功异常" + str(e))
|
|
frame = Frame(root, {"height": 280, "width": 300, "bg": "#DDDDDD"})
|
frame.grid(row=2, column=2, rowspan=2, pady=5)
|
btntext = StringVar()
|
|
el = Label(frame, text="测试区域", bg="#DDDDDD", fg="#A0A000")
|
el.place(x=240, y=10)
|
|
el = Label(frame, text="客户端ID:", bg="#DDDDDD")
|
el.place(x=10, y=10)
|
ep_client = Entry(frame, width=2)
|
ep_client.place(x=70, y=10)
|
|
el = Label(frame, text="位置:", bg="#DDDDDD")
|
el.place(x=10, y=40)
|
ep = Entry(frame, width=2)
|
ep.place(x=50, y=40)
|
|
cl = Label(frame, text="代码:", bg="#DDDDDD")
|
cl.place(x=10, y=70)
|
code = Entry(frame)
|
code.place(x=50, y=70)
|
|
btn = FlatButton(frame, text="设置代码", command=lambda: setGPCode(ep_client.get(), ep.get(), code.get()), )
|
btn.place(x=10, y=100)
|
|
btn = FlatButton(frame, text="修复L2数据", command=lambda: L2CodeOperate.get_instance().repaire_l2_data(code.get()))
|
btn.place(x=70
|
, y=100)
|
|
btn = FlatButton(frame, text="导出L2数据", command=lambda: export_l2_data(code.get()))
|
btn.place(x=145, y=100)
|
|
btn = FlatButton(frame, text="导出L2原始数据", command=lambda: export_l2_data_origin(code.get()))
|
btn.place(x=220, y=100)
|
|
btn = FlatButton(frame, text="获取m值", command=lambda: compute_m(code.get()))
|
btn.place(x=10, y=130)
|
|
btn = FlatButton(frame, text="导出交易日志", command=lambda: log.export_l2_log(code.get()))
|
btn.place(x=80, y=130)
|
|
btn = FlatButton(frame, text="清空l2数据", command=lambda: clear_l2(code.get()))
|
btn.place(x=150, y=130)
|
|
btn = FlatButton(frame, text="撤销挂单", command=lambda: cancel_order(code.get()))
|
btn.place(x=230, y=130)
|
|
# 交易按钮
|
btn = FlatButton(frame, textvariable=btntext, command=startJueJinGui)
|
btn.place(x=10, y=160)
|
btntext.set("启动掘金")
|
|
btn = FlatButton(frame, text="重新订阅行情", command=resub)
|
btn.place(x=10, y=190)
|
|
btn = FlatButton(frame, text="刷新窗口句柄", command=refresh_hwnds)
|
btn.place(x=200, y=190)
|
|
def create_gui(self):
|
|
root = Tk()
|
root.title("自动化交易系统")
|
root.resizable(height=False, width=False)
|
|
self.__draw_juejin(root)
|
self._draw_check(root)
|
self.__draw_l2_state(root)
|
self.__draw_trade_state(root)
|
self.__draw_trade_data(root)
|
self.__draw_test(root)
|
|
root.geometry("1120x660")
|
root.mainloop()
|
|
|
if __name__ == '__main__':
|
listen = gpcode_manager.is_listen("000333")
|
print(listen)
|
# 启动掘金任务
|
GUI().run()
|