From 045a5aa6434da6e83c3d850b17e7e58cd7b55ef5 Mon Sep 17 00:00:00 2001
From: Administrator <admin@example.com>
Date: 星期一, 15 五月 2023 15:46:32 +0800
Subject: [PATCH] 开盘啦板块影响交易逻辑

---
 output/index.html                    |    2 
 third_data/kpl_api.py                |   39 +
 log.py                               |   52 +
 third_data/kpl_data_manager.py       |  109 ++++
 constant.py                          |    7 
 output/limit_up_data_filter.py       |   85 +++
 server.py                            |   51 ++
 output/css/index.css                 |    4 
 output/output_util.py                |   14 
 third_data/data_server.py            |  280 ++++++++++++
 third_data/block_info.py             |   24 
 tool.py                              |   12 
 trade/trade_manager.py               |   16 
 third_data/code_plate_key_manager.py |  240 ++++++++++
 ui/my_widget.py                      |   15 
 gui.py                               |   73 +-
 ths_industry_util.py                 |    2 
 third_data/kpl_util.py               |   68 ++
 l2/l2_data_manager_new.py            |   44 +
 output/code_info_output.py           |  154 ++----
 20 files changed, 1,077 insertions(+), 214 deletions(-)

diff --git a/constant.py b/constant.py
index 5ad950f..6b903e4 100644
--- a/constant.py
+++ b/constant.py
@@ -4,7 +4,7 @@
 TRADE_ENABLE = False
 
 # 鏄惁闇�瑕佹姤璀�
-NEED_ALERT =True
+NEED_ALERT = False
 
 # 姘翠笅鎹炵疮璁¤繛缁按涓嬫椂闂存渶灏忓��
 UNDER_WATER_PRICE_TIME_AS_SECONDS = 1200
@@ -34,8 +34,11 @@
 L2_CODE_COUNT_PER_DEVICE = 6
 
 # 涔板叆鍒嗘暟鍒嗘。
-BUY_SCORE_RANK_0 = 170
+BUY_SCORE_RANK_0 = 150
 BUY_SCORE_RANK_1 = 220
 BUY_SCORE_RANK_2 = 240
 BUY_SCORE_RANK_3 = 260
 
+# 寮�鐩樺暒
+KPL_INVALID_BLOCKS = ["涓�瀛f姤澧為暱", "浜屽鎶ュ闀�", "涓夊鎶ュ闀�", "鍥涘鎶ュ闀�", "涓氱哗澧為暱", "涓姤澧為暱", "骞存姤澧為暱", "骞存姤棰勫", "鏃�", "娆℃柊鑲�", "ST鎽樺附", "瓒呰穼",
+                      "鑲℃潈杞", "骞惰喘閲嶇粍", "鍐嶈瀺璧�", "骞存姤棰勫", "娆℃柊鑲�", " 涓撶簿鐗规柊", "澹宠祫婧�"]
diff --git a/gui.py b/gui.py
index 6282b5e..9fe9591 100644
--- a/gui.py
+++ b/gui.py
@@ -22,13 +22,14 @@
 from trade import l2_trade_util
 from trade.l2_trade_factor import L2TradeFactorUtil
 from ocr import ocr_server
-from third_data import  data_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):
@@ -217,7 +218,7 @@
         text = Text(frame, height=100, undo=True)
         text.place(x=0, y=40)
 
-        btn = Button(frame, text="杩愯鐜妫�娴�", command=click)
+        btn = FlatButton(frame, text="杩愯鐜妫�娴�", command=click)
         btn.place(x=5, y=5)
 
         frame.grid(row=1, column=2)
@@ -303,20 +304,27 @@
                 # 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 = Button(frame, text="鍒锋柊鏀剁洏浠�", command=refresh_close_price_data)
+        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 = Button(frame, text="閲嶆柊鑾峰彇鏀剁洏浠�", command=re_get_close_price)
-        btn.place(x=130, y=start_y)
-
-        btn = Button(frame, text="浠婃棩娑ㄥ仠", command=get_limit_up_codes_win)
-        btn.place(x=250, y=start_y)
+        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)
@@ -332,7 +340,7 @@
         refresh_trade_buy_win_data()
         refresh_close_price_data()
 
-        btn = Button(frame, text="鍒锋柊", command=refresh_trade_buy_win_data, height=1)
+        btn = FlatButton(frame, text="鍒锋柊", command=refresh_trade_buy_win_data)
         btn.place(x=450 - 35, y=start_y)
 
         def re_distribute_buy_win():
@@ -348,7 +356,7 @@
             except Exception as e:
                 showerror("鍒嗛厤鍑洪敊", str(e))
 
-        btn = Button(frame, text="閲嶆柊鍒嗛厤绐楀彛", command=re_distribute_buy_win, height=1)
+        btn = FlatButton(frame, text="閲嶆柊鍒嗛厤绐楀彛", command=re_distribute_buy_win)
         btn.place(x=450 - 83, y=start_y + 30)
 
     # 缁樺埗浜ゆ槗鐘舵��
@@ -436,7 +444,7 @@
 
         start_y = 285
 
-        btn = Button(frame, text="鍒锋柊鐘舵��", command=refresh_data)
+        btn = FlatButton(frame, text="鍒锋柊鐘舵��", command=refresh_data)
         btn.place(x=10, y=start_y)
 
         auo_refresh = IntVar()
@@ -579,7 +587,7 @@
             win.resizable(height=False, width=False)
             text = Text(win, height=100, undo=True)
             text.place(x=0, y=30)
-            btn = Button(win, text="涓�閿慨澶�", command=repair)
+            btn = FlatButton(win, text="涓�閿慨澶�", command=repair)
             btn.place(x=0, y=0)
 
             line = 0
@@ -652,10 +660,10 @@
         else:
             accept_l2.set(0)
 
-        btn = Button(frame, text="姣忔棩鍒濆鍖�", command=init)
+        btn = FlatButton(frame, text="姣忔棩鍒濆鍖�", command=init)
         btn.place(x=width - 250, y=5)
 
-        btn = Button(frame, text="鍒锋柊鏁版嵁", command=refresh_data)
+        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",
@@ -676,16 +684,17 @@
         menu.add_command(label="鐜妫�娴�", command=check_env)
         menu.add_command(label="鍚岃姳椤烘祴閫�", command=ths_test_speed)
 
+        device_index =0
         for key in self.l2_codes:
-
-            client_lb = Label(frame, text="璁惧:{}".format(key), background="#DDDDDD")
+            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 = Button(frame, text="妫�娴�", command=key)
+            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=82, y=40 + l2_client_count * 30)
+            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] = []
@@ -697,7 +706,7 @@
                 code_labels[key].append(code_label)
 
                 code_label.place(x=0, y=0)
-                cframe.place(x=200 + i * 85, y=40 + l2_client_count * 30)
+                cframe.place(x=250 + i * 85, y=40 + l2_client_count * 30)
             l2_client_count += 1
         # 娣诲姞鏇存柊绾跨▼
         t1 = threading.Thread(target=lambda: update_data())
@@ -794,7 +803,7 @@
         cl = Label(frame, textvariable=sv_trade_money, bg="#DDDDDD", fg="#666666")
         cl.place(x=190, y=5)
 
-        btn = Button(frame, text="鍒锋柊鏁版嵁", command=refresh_data)
+        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",
@@ -887,7 +896,7 @@
         entry = Entry(frame, textvariable=token_var, width=30)
         entry.place(x=left + 60, y=top + 60)
 
-        btn = Button(frame, text="璁剧疆鎺橀噾鍙傛暟", command=click)
+        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)
@@ -991,40 +1000,40 @@
         code = Entry(frame)
         code.place(x=50, y=70)
 
-        btn = Button(frame, text="璁剧疆浠g爜", command=lambda: setGPCode(ep_client.get(), ep.get(), code.get()), )
+        btn = FlatButton(frame, text="璁剧疆浠g爜", command=lambda: setGPCode(ep_client.get(), ep.get(), code.get()), )
         btn.place(x=10, y=100)
 
-        btn = Button(frame, text="淇L2鏁版嵁", command=lambda: L2CodeOperate.get_instance().repaire_l2_data(code.get()))
+        btn = FlatButton(frame, text="淇L2鏁版嵁", command=lambda: L2CodeOperate.get_instance().repaire_l2_data(code.get()))
         btn.place(x=70
                   , y=100)
 
-        btn = Button(frame, text="瀵煎嚭L2鏁版嵁", command=lambda: export_l2_data(code.get()))
+        btn = FlatButton(frame, text="瀵煎嚭L2鏁版嵁", command=lambda: export_l2_data(code.get()))
         btn.place(x=145, y=100)
 
-        btn = Button(frame, text="瀵煎嚭L2鍘熷鏁版嵁", command=lambda: export_l2_data_origin(code.get()))
+        btn = FlatButton(frame, text="瀵煎嚭L2鍘熷鏁版嵁", command=lambda: export_l2_data_origin(code.get()))
         btn.place(x=220, y=100)
 
-        btn = Button(frame, text="鑾峰彇m鍊�", command=lambda: compute_m(code.get()))
+        btn = FlatButton(frame, text="鑾峰彇m鍊�", command=lambda: compute_m(code.get()))
         btn.place(x=10, y=130)
 
-        btn = Button(frame, text="瀵煎嚭浜ゆ槗鏃ュ織", command=lambda: log.export_l2_log(code.get()))
+        btn = FlatButton(frame, text="瀵煎嚭浜ゆ槗鏃ュ織", command=lambda: log.export_l2_log(code.get()))
         btn.place(x=80, y=130)
 
-        btn = Button(frame, text="娓呯┖l2鏁版嵁", command=lambda: clear_l2(code.get()))
+        btn = FlatButton(frame, text="娓呯┖l2鏁版嵁", command=lambda: clear_l2(code.get()))
         btn.place(x=150, y=130)
 
-        btn = Button(frame, text="鎾ら攢鎸傚崟", command=lambda: cancel_order(code.get()))
+        btn = FlatButton(frame, text="鎾ら攢鎸傚崟", command=lambda: cancel_order(code.get()))
         btn.place(x=230, y=130)
 
         # 浜ゆ槗鎸夐挳
-        btn = Button(frame, textvariable=btntext, command=startJueJinGui)
+        btn = FlatButton(frame, textvariable=btntext, command=startJueJinGui)
         btn.place(x=10, y=160)
         btntext.set("鍚姩鎺橀噾")
 
-        btn = Button(frame, text="閲嶆柊璁㈤槄琛屾儏", command=resub)
+        btn = FlatButton(frame, text="閲嶆柊璁㈤槄琛屾儏", command=resub)
         btn.place(x=10, y=190)
 
-        btn = Button(frame, text="鍒锋柊绐楀彛鍙ユ焺", command=refresh_hwnds)
+        btn = FlatButton(frame, text="鍒锋柊绐楀彛鍙ユ焺", command=refresh_hwnds)
         btn.place(x=200, y=190)
 
     def create_gui(self):
diff --git a/l2/l2_data_manager_new.py b/l2/l2_data_manager_new.py
index 641bc1c..caf67cd 100644
--- a/l2/l2_data_manager_new.py
+++ b/l2/l2_data_manager_new.py
@@ -15,7 +15,8 @@
 from db import redis_manager
 import ths_industry_util
 import tool
-from trade import  trade_manager, trade_queue_manager, l2_trade_factor, l2_trade_util, \
+from third_data.code_plate_key_manager import CodePlateKeyBuyManager
+from trade import trade_manager, trade_queue_manager, l2_trade_factor, l2_trade_util, \
     trade_result_manager, first_code_score_manager
 from l2 import safe_count_manager, l2_data_manager, l2_data_log, l2_log, l2_data_source_util, code_price_manager
 from l2.cancel_buy_strategy import SecondCancelBigNumComputer, HourCancelBigNumComputer, L2LimitUpMoneyStatisticUtil, \
@@ -361,7 +362,8 @@
         def h_cancel():
             _start_time = round(t.time() * 1000)
             try:
-                b_need_cancel, b_cancel_data = HourCancelBigNumComputer.need_cancel(code,buy_single_index, buy_exec_index, start_index,
+                b_need_cancel, b_cancel_data = HourCancelBigNumComputer.need_cancel(code, buy_single_index,
+                                                                                    buy_exec_index, start_index,
                                                                                     end_index, total_data,
                                                                                     local_today_num_operate_map.get(
                                                                                         code),
@@ -680,6 +682,7 @@
         if buy1_price is None:
             return False, True, f"灏氭湭鑾峰彇鍒颁拱1浠�"
         limit_up_price = gpcode_manager.get_limit_up_price(code)
+
         dif = float(limit_up_price) - float(buy1_price)
         if zyltgb >= 80 * 100000000:
             # 澶т簬2妗�
@@ -719,6 +722,14 @@
 
         if not gpcode_manager.WantBuyCodesManager.is_in(code):
 
+            if float(limit_up_price) >= 40:
+                return False, True, "鑲′环澶т簬40鍧�"
+
+            # 鍒ゆ柇鏉垮潡
+            plate_can_buy, msg = CodePlateKeyBuyManager.can_buy(code)
+            if not plate_can_buy:
+                return False, True, msg
+
             # 鏌ョ湅鍒嗘暟绛夌骇
             score_index = cls.__l2PlaceOrderParamsManagerDict[code].score_index
             score = cls.__l2PlaceOrderParamsManagerDict[code].score
@@ -737,27 +748,20 @@
             limit_up_time = score_info[1][7]
             if limit_up_time is None:
                 limit_up_time = tool.get_now_time_str()
-            if int(limit_up_time.replace(":", "")) > int("143000"):
-                if not score_info[1][3][6][0]:
-                    return False, True, f"灏剧洏鍋疯窇:鏃犱换浣曞舰鎬�"
-                if score_info[1][5]["limit_up_codes_count"] > 1:
-                    return False, True, f"灏剧洏鍋疯窇:鏉垮潡{score_info[1][5]['target_block_info'][0]}-娑ㄥ仠鏁皗score_info[1][5]['limit_up_codes_count']}"
-                if float(gpcode_manager.get_limit_up_price(code)) > 30:
-                    return False, True, f"灏剧洏鍋疯窇:鑲′环澶т簬30"
+
+            # 灏剧洏鍋疯窇鏆傛椂涓嶈
+            # if int(limit_up_time.replace(":", "")) > int("143000"):
+            #     if not score_info[1][3][6][0]:
+            #         return False, True, f"灏剧洏鍋疯窇:鏃犱换浣曞舰鎬�"
+            #     if score_info[1][5]["limit_up_codes_count"] > 1:
+            #         return False, True, f"灏剧洏鍋疯窇:鏉垮潡{score_info[1][5]['target_block_info'][0]}-娑ㄥ仠鏁皗score_info[1][5]['limit_up_codes_count']}"
+            #     if float(gpcode_manager.get_limit_up_price(code)) > 30:
+            #         return False, True, f"灏剧洏鍋疯窇:鑲′环澶т簬30"
 
             if score_index < 0:
                 return False, True, f"鍒嗗�硷細{score}鏈揪鍒伴渶瑕佷拱鍏ョ殑鍒嗘暟绾�"
-            if score_index >= 3:
-                return False, True, f"鍒嗗�硷細{score}鏈揪鍒颁富鍔ㄤ拱鍏ュ垎鏁扮嚎"
-            return True, False, ""
-            # if -1 < score_index < 3 and (0.499 <= cls.volume_rate_info[code][0] <= 0.949):
-            #     return True, False, f"鍒嗗�硷細{score}杈惧埌涓诲姩涔板叆鐨勫垎鏁扮嚎涓旈噺瓒冲锛屼拱鍏ョ瓑绾э細f{score_index},閲忔瘮锛歿cls.volume_rate_info[code][0]}"
-            is_limited_up = gpcode_manager.FirstCodeManager.is_limited_up(code)
-            gpcode_manager.FirstCodeManager.add_limited_up_record([code])
-            if not code_price_manager.Buy1PriceManager.is_can_buy(code):
-                return False, True, f"棣栨澘浠g爜锛屾病鍦ㄦ兂瑕佷拱鍚嶅崟涓笖鏈墦寮�娑ㄥ仠鏉�,鍒嗘暟锛歿score}"
-            if not is_limited_up:
-                return False, True, f"棣栨澘浠g爜锛屾病鍦ㄦ兂瑕佷拱鍚嶅崟涓笖鏈定鍋滆繃,鍒嗘暟锛歿score}"
+            # if score_index >= 3:
+            #     return False, True, f"鍒嗗�硷細{score}鏈揪鍒颁富鍔ㄤ拱鍏ュ垎鏁扮嚎"
             return True, False, ""
         else:
             return True, False, "鍦ㄦ兂涔板悕鍗曚腑"
diff --git a/log.py b/log.py
index 04c5562..821e70d 100644
--- a/log.py
+++ b/log.py
@@ -134,6 +134,14 @@
                    filter=lambda record: record["extra"].get("name") == "place_order_score",
                    rotation="00:00", compression="zip", enqueue=True)
 
+        logger.add(self.get_path("kpl", "kpl_limit_up_reason_change"),
+                   filter=lambda record: record["extra"].get("name") == "kpl_limit_up_reason_change",
+                   rotation="00:00", compression="zip", enqueue=True)
+
+        logger.add(self.get_path("kpl", "kpl_limit_up"),
+                   filter=lambda record: record["extra"].get("name") == "kpl_limit_up",
+                   rotation="00:00", compression="zip", enqueue=True)
+
     def get_path(self, dir_name, log_name):
         return "D:/logs/gp/{}/{}".format(dir_name, log_name) + ".{time:YYYY-MM-DD}.log"
 
@@ -184,6 +192,11 @@
 logger_trade_record = __mylogger.get_logger("trade_record")
 
 logger_place_order_score = __mylogger.get_logger("place_order_score")
+
+logger_kpl_limit_up_reason_change = __mylogger.get_logger("kpl_limit_up_reason_change")
+
+logger_kpl_limit_up = __mylogger.get_logger("kpl_limit_up")
+
 
 class LogUtil:
     @classmethod
@@ -372,12 +385,13 @@
 
 def export_logs(code):
     code_name = gpcode_manager.get_code_name(code)
-    date =  datetime.datetime.now().strftime("%Y-%m-%d")
+    date = datetime.datetime.now().strftime("%Y-%m-%d")
     target_dir = f"D:/logs/gp/l2/export/{code}_{code_name}_{date}"
     if os.path.exists(target_dir):
         shutil.rmtree(target_dir)
     os.makedirs(target_dir)
-    log_names = ["l2_process", "l2_trade", "l2_trade_cancel", "l2_process_time", "l2_trade_buy", "l2_trade_buy_progress", "cancel/h_cancel"]
+    log_names = ["l2_process", "l2_trade", "l2_trade_cancel", "l2_process_time", "l2_trade_buy",
+                 "l2_trade_buy_progress", "cancel/h_cancel"]
     # 瀵煎嚭浜ゆ槗鏃ュ織
     for log_name in log_names:
         key = f"code={code}"
@@ -391,20 +405,19 @@
         LogUtil.extract_log_from_key(key, f"D:/logs/gp/l2/{log_name}.{date}.log",
                                      target_path)
 
+
 def export_trade_progress(code):
-    path =f"D:/logs/gp/l2/l2_trade_buy_progress.{tool.get_now_date_str()}.log"
-    index_set=set()
-    with open(path,mode='r',encoding="utf-8") as f:
+    path = f"D:/logs/gp/l2/l2_trade_buy_progress.{tool.get_now_date_str()}.log"
+    index_set = set()
+    with open(path, mode='r', encoding="utf-8") as f:
         lines = f.readlines()
         for line in lines:
-            if line.find(f"code-{code}") > -1 and line.find("纭畾浜ゆ槗杩涘害鎴愬姛")>-1:
-                index= line.split("index-")[1].split(" ")[0]
+            if line.find(f"code-{code}") > -1 and line.find("纭畾浜ゆ槗杩涘害鎴愬姛") > -1:
+                index = line.split("index-")[1].split(" ")[0]
                 index_set.add(int(index))
     results = list(index_set)
     results.sort()
     return results
-
-
 
 
 # 鍔犺浇涔板叆寰楀垎璁板綍
@@ -420,14 +433,27 @@
                     time_str = line[11:19]
                     data = line[line.find("data=") + 5:]
                     type = line[line.find("type=") + 5:line.find(" ", line.find("type="))]
-                    fdatas.append((time_str, type, eval("{"+data+"}")))
+                    fdatas.append((time_str, type, eval("{" + data + "}")))
+    return fdatas
+
+
+def load_kpl_reason_changes():
+    path = f"D:/logs/gp/kpl/kpl_limit_up_reason_change.{tool.get_now_date_str()}.log"
+    fdatas = []
+    if os.path.exists(path):
+        with open(path, 'r', encoding="utf-8") as f:
+            lines = f.readlines()
+            for line in lines:
+                data = line[line.find("code-") + 5:]
+                code = data.split(":")[0]
+                from_r = data.split(":")[1].split("-")[0]
+                to_r = eval(data.split(":")[1].split("-")[1])
+                fdatas.append((code, from_r, to_r))
     return fdatas
 
 
 if __name__ == '__main__':
-    print(logger_place_order_score.info("002681"))
-
-
+    print(load_kpl_reason_changes())
 
     # logger_l2_h_cancel.info("test")
     # logger_l2_process_time.info("test123")
diff --git a/output/code_info_output.py b/output/code_info_output.py
index 2924830..8003c61 100644
--- a/output/code_info_output.py
+++ b/output/code_info_output.py
@@ -55,12 +55,17 @@
 
 
 def get_output_html(code):
-    def money_desc(money):
-        if money > 100000000:
-            return f"{round(money / 100000000, 2)}浜�"
-        else:
-            return f"{round(money / 10000, 2)}涓�"
+    return render(get_output_params(code))
 
+
+def money_desc(money):
+    if money > 100000000:
+        return f"{round(money / 100000000, 2)}浜�"
+    else:
+        return f"{round(money / 10000, 2)}涓�"
+
+
+def get_output_params(code):
     params = {
         "base_url": "http://192.168.3.252/kp/",
     }
@@ -111,7 +116,8 @@
         deal_indexes = trade.deal_big_money_manager.get_traded_indexes(code)
         deal_info = ""
         params["score_data"]["deal_big_money"] = {"score": score_list[8], "money": score_source_list[8][0] // 10000,
-                                                  "base_money": score_source_list[8][1] // 10000}
+                                                  "base_money": score_source_list[8][1] // 10000,
+                                                  "rate": round(score_source_list[8][0] / score_source_list[8][1], 2)}
         if deal_indexes:
             temps = []
             for index in deal_indexes:
@@ -135,28 +141,28 @@
         for k in range(0, len(score_source_list[3])):
             if k == 0:
                 if score_source_list[3][k][0]:
-                    k_source.append("娑ㄥ箙杩囬珮")
+                    k_source.append(("娑ㄥ箙杩囬珮", score_list[3][k]))
             elif k == 1:
                 if score_source_list[3][k][0]:
-                    k_source.append("绐佺牬鍓嶉珮")
+                    k_source.append(("绐佺牬鍓嶉珮", score_list[3][k]))
             elif k == 2:
                 if score_source_list[3][k][0]:
-                    k_source.append("瓒呰穼琛ユ定")
+                    k_source.append(("瓒呰穼琛ユ定", score_list[3][k]))
             elif k == 3:
                 if score_source_list[3][k][0]:
-                    k_source.append(f"閫艰繎鍓嶉珮-{score_source_list[3][k][1]}銆�")
+                    k_source.append((f"閫艰繎鍓嶉珮-{score_source_list[3][k][1]}銆�", score_list[3][k]))
             elif k == 4:
                 if score_source_list[3][k][0]:
-                    k_source.append("N瀛楀瀷")
+                    k_source.append(("N瀛楀瀷", score_list[3][k]))
             elif k == 5:
                 if score_source_list[3][k][0]:
-                    k_source.append("V瀛楀瀷")
+                    k_source.append(("V瀛楀瀷", score_list[3][k]))
             elif k == 6:
                 if not score_source_list[3][k][0]:
-                    k_source.append("涓嶆弧瓒充换浣曞舰鎬�")
+                    k_source.append(("涓嶆弧瓒充换浣曞舰鎬�", score_list[3][k]))
             elif k == 7:
                 if score_source_list[3][k][0]:
-                    k_source.append("澶╅噺澶ч槼")
+                    k_source.append(("澶╅噺澶ч槼", score_list[3][k]))
 
         params["score_data"]["k_form"] = {"score": k_score, "datas": k_source}
 
@@ -166,21 +172,27 @@
         for k in score_list[4]:
             nature_score += k
 
+        code_nature_datas = {"score": nature_score, "limit_up_count": score_source_list[4][0]}
+
         for n in range(0, len(score_source_list[4])):
             if n == 0:
                 nature_source.append(f"娑ㄥ仠娆℃暟銆恵score_source_list[4][n]}銆�")
             elif n == 1:
                 if score_source_list[4][n]:
                     nature_source.append(f"棣栨澘婧环鐜囥�恵round(score_source_list[4][n], 2)}銆�")
+                    code_nature_datas["first_limit_up_yijia"] = round(score_source_list[4][1], 2)
                 else:
                     nature_source.append(f"鏃犻鏉�")
+                    code_nature_datas["first_limit_up_yijia"] = "鏃犻鏉�"
             elif n == 2:
                 if score_source_list[4][n]:
                     nature_source.append(f"棣栨澘鐐告澘婧环鐜囥�恵round(score_source_list[4][n], 2)}銆�")
+                    code_nature_datas["first_open_limit_up_yijia"] = round(score_source_list[4][2], 2)
                 else:
                     nature_source.append(f"鏃犻鏉跨偢鏉�")
+                    code_nature_datas["first_open_limit_up_yijia"] = "鏃犻鏉跨偢鏉�"
 
-        params["score_data"]["code_nature"] = {"score": nature_score, "data_desc": ",".join(nature_source)}
+        params["score_data"]["code_nature"] = code_nature_datas
 
         # 鏉垮潡鐑害
         hot_block_score = 0
@@ -208,6 +220,7 @@
                                              "limit_up_index": hot_block_source_data['limit_up_index'] + 1,
                                              "block_name": hot_block_source_data['target_block_info'][0],
                                              "limit_up_count": hot_block_source_data['limit_up_codes_count'],
+                                             "block_history_count": hot_block_source_data['target_block_info'][2],
                                              "open_limit_up_count": hot_block_source_data['break_size']}
 
         # 涓婃澘鏃堕棿
@@ -262,7 +275,7 @@
             global_data_loader.load_zyltgb()
             zyltgb = global_util.zyltgb_map.get(code)
         base_m = L2TradeFactorUtil.get_base_safe_val(zyltgb)
-        params["trade_data"]["m_val"] = {"base": base_m // 10000, "now": m[0] // 10000},
+        params["trade_data"]["m_val"] = {"base": base_m // 10000, "now": m[0] // 10000}
         # 涔板墠澶у崟
         big_num = __L2PlaceOrderParamsManager.get_big_num_count()
         base_big_num = __base_L2PlaceOrderParamsManager.get_big_num_count()
@@ -315,14 +328,7 @@
             elif trade_state == trade_manager.TRADE_STATE_BUY_SUCCESS:
                 params["trade_data"]["trade_state"]["desc"] = "宸叉垚浜�"
 
-    ##############################閫夎偂瀹�##################################
-
-    params["xgb_code_infos"] = []
-
-    ##############################鐑棬椋庡彛##################################
-
-    params["xgb_infos"] = []
-
+    ##############################涓诲姩涔帮紝琚姩涔�##################################
     # 杩斿洖涓诲姩涔�,琚姩涔�,涓嶄拱鐨勫垪琛�(浠g爜, 鍚嶇О, 寰楀垎, 鏄惁娑ㄥ仠)
     codes_score = __load_codes_scores()
     params["initiative_buy_codes"] = []
@@ -334,12 +340,23 @@
     for d in codes_score[1]:
         params["passive_buy_codes"].append(
             {"name": d[1], "code": d[0], "score": d[2], "limit_up": d[3], "open_limit_up": d[4]})
+    # 涓诲姩涔颁笌琚姩涔颁笉鑳借秴杩�11琛�
+    initiative_count = len(params["initiative_buy_codes"])
+    passive_count = len(params["passive_buy_codes"])
+    buy_row = 0
+    buy_row += initiative_count // 3
+    if initiative_count % 3 > 0:
+        buy_row += 1
+    max_passive_count = (10 - buy_row) * 3
+    if max_passive_count < 0:
+        max_passive_count = 0
+    params["passive_buy_codes"] = params["passive_buy_codes"][:max_passive_count]
 
     trade_info = __load_trade_record(code, total_datas)
     params["trade_record"] = {"open_limit_up": trade_info[0], "records": trade_info[2]}
 
     ##############################寮�鐩樺暒鐩稿叧淇℃伅##################################
-    params["kpl_code_info"] = {}
+    params["kpl_code_info"] = {"industry":global_util.code_industry_map.get(code)}
     # 鑾峰彇寮�鐩樺暒鏉垮潡
     plate_info = kpl_api.getStockIDPlate(code)
     if plate_info:
@@ -347,85 +364,18 @@
         plate_info.reverse()
         params["kpl_code_info"]["plate"] = plate_info
 
-    # 鑾峰彇浠g爜鐨勫巻鍙叉定鍋滄暟鎹�
-    params["kpl_code_info"]["code_records"] = KPLLimitUpDataRecordManager.get_latest_infos(code, 4)
+    # 鑾峰彇浠g爜鐨勫巻鍙叉定鍋滄暟鎹�,(娑ㄥ仠鍘熷洜,鏃ユ湡,鏉垮潡)
+    params["kpl_code_info"]["code_records"] = KPLLimitUpDataRecordManager.get_latest_infos(code, 4, False)[:2]
 
-    # 鑾峰彇浠婃棩鏉垮潡
-    block = block_info.get_target_block(code, False)
-    if block is None:
-        block = "鏃犳澘鍧�"
-    # 鑾峰彇鏈�杩戠殑4涓氦鏄撴棩
-    today = tool.get_now_date_str()
-    days = []
-    day = today
-    for i in range(3):
-        day = juejin.JueJinManager.get_previous_trading_date(day)
-        days.append(day)
-    days.insert(0, today)
-    # 鑾峰彇杩欏嚑澶╃殑娑ㄥ仠浠g爜
-    kpl_record_datas = {}
-    for d in days:
-        tem_datas = KPLLimitUpDataRecordManager.list_by_block(block, d)
-        tem_datas = list(tem_datas)
-        # 鏍规嵁娑ㄥ仠鏃堕棿鎺掑簭
-        tem_datas.sort(key=lambda x: int(x[5]))
+    if not KPLLimitUpDataRecordManager.total_datas:
+        KPLLimitUpDataRecordManager.load_total_datas()
+    for d in KPLLimitUpDataRecordManager.total_datas:
+        if d[3] == code:
+            # 鑾峰彇浠婃棩
+            params["kpl_code_info"]["today"] = (d[2], d[1], d[6])
+            break
 
-        kpl_record_datas[d] = {"codes": [], "hot_block": block, "index": -1, "limit_up_count": 0}
-        for i in range(len(tem_datas)):
-            temp = tem_datas[i]
-            __code = temp[3]
-            kpl_record_datas[d]["codes"].append(
-                {"name": temp[4], "code": __code, "limit_up": False, "open_limit_up": False,"ss":(__code.find("00")==0 or __code.find("60")==0) })
-            if __code == code:
-                kpl_record_datas[d]["blocks"] = temp[6].split("銆�")
-                kpl_record_datas[d]["index"] = i + 1
-                kpl_record_datas[d]["limit_up_time"] = time.strftime("%H:%M:%S", time.localtime(int(temp[5])))
-    # 鑾峰彇浠婃棩浠g爜鐨勫緱鍒�
-    __score_dict = {}
-    for fs in codes_score:
-        for s in fs:
-            # (寰楀垎,鏄惁娑ㄥ仠)
-            __score_dict[s[0]] = (s[2], s[3])
-    # 鑾峰彇鍒嗗��
-    for d in kpl_record_datas[today]["codes"]:
-        __code = d["code"]
-        if __code in __score_dict:
-            d["score"] = __score_dict[__code][0]
-    # 鑾峰彇鏄惁娑ㄥ仠,缁熻娑ㄥ仠鏁伴噺
-    for d in kpl_record_datas:
-        # 鑾峰彇娑ㄥ仠浠g爜淇℃伅
-        limit_up_datas = __kplDataManager.get_from_file(kpl_util.KPLDataType.LIMIT_UP, d)
-        if limit_up_datas is None:
-            limit_up_datas = []
-        limit_up_codes = set([x[0] for x in limit_up_datas])
-        limit_up_count = 0
-        for code_info in kpl_record_datas[d]["codes"]:
-            __code = code_info["code"]
-            if __code in limit_up_codes:
-                code_info["limit_up"] = True
-                code_info["open_limit_up"] = False
-                limit_up_count += 1
-            else:
-                code_info["limit_up"] = False
-                code_info["open_limit_up"] = True
-        kpl_record_datas[d]["limit_up_count"] = limit_up_count
-
-    block_records = [[key, kpl_record_datas[key]] for key in kpl_record_datas]
-    block_records.sort(key=lambda x: x[0])
-    block_records.reverse()
-    for i in range(len(block_records)):
-        if i == 0:
-            block_records[i][0] = "浠婂ぉ"
-        elif i == 1:
-            block_records[i][0] = "鏄ㄥぉ"
-        elif i == 2:
-            block_records[i][0] = "鍓嶅ぉ"
-        elif i == 3:
-            block_records[i][0] = "涔嬪墠"
-
-    params["kpl_code_info"]["block_records"] = block_records
-
-    return render(params)
+    return params
 
 
 def __load_codes_scores():
diff --git a/output/css/index.css b/output/css/index.css
index 51d606e..3b87b96 100644
--- a/output/css/index.css
+++ b/output/css/index.css
@@ -77,9 +77,9 @@
 }
 
 .table-name {
-	height: 30px;
+	height: 50px;
 	width: 520px;
-	line-height: 30px;
+	line-height: 50px;
 	padding-left: 10px;
 	margin-top: 12px;
 	font-size: 16px;
diff --git a/output/index.html b/output/index.html
index cc38f23..33a5641 100644
--- a/output/index.html
+++ b/output/index.html
@@ -158,7 +158,7 @@
 					<span class="bold">{{trade_data.star.desc}}</span>
 					{% endif %}
 					{% for i in range(0,trade_data.star.count) %}
-					<img src="{{base_url}}images/star.png" / style="margin-left: 3px;"></span>
+					<img src="{{base_url}}images/star.png"  style="margin-left: 3px;"></span>
 					{% endfor %}
 				</td>
 			</tr>
diff --git a/output/limit_up_data_filter.py b/output/limit_up_data_filter.py
new file mode 100644
index 0000000..ea45a6b
--- /dev/null
+++ b/output/limit_up_data_filter.py
@@ -0,0 +1,85 @@
+"""
+娑ㄥ仠鏁版嵁杩囨护鍣�
+"""
+
+# 鍒ゆ柇鏄緳鍑狅紝鍒ゆ柇鏄惁娑ㄥ仠锛屽垽鏂槸鍚︾偢鏉匡紝鍔犺浇鍒嗘暟
+import redis
+
+import code_volumn_manager
+import gpcode_manager
+import limit_up_time_manager
+import tool
+from db import redis_manager
+from third_data.kpl_data_manager import KPLDataManager
+from third_data.kpl_util import KPLDataType
+from trade import first_code_score_manager
+
+__kplDataManager = KPLDataManager()
+
+
+# 蹇界暐浠g爜绠$悊鍣�
+class IgnoreCodeManager:
+    __redisManager = redis_manager.RedisManager(3)
+
+    def __get_redis(self):
+        return self.__redisManager.getRedis()
+
+    def ignore_code(self, type, code):
+        self.__get_redis().sadd(f"kp_ignore_codes_{type}", code)
+        self.__get_redis().expire(f"kp_ignore_codes_{type}", tool.get_expire())
+
+    def list_ignore_codes(self, type):
+        return self.__get_redis().smembers(f"kp_ignore_codes_{type}")
+
+
+# 鑾峰彇娑ㄥ仠椤哄簭锛堟寜娑ㄥ仠鍘熷洜鍒嗙粍锛�
+def get_limit_up_time_rank_dict(datas):
+    datas.sort(key=lambda x: int(x[5]))
+    max_record = {}
+    rank_dict = {}
+    for d in datas:
+        if d[2] not in max_record:
+            max_record[d[2]] = 0
+        max_record[d[2]] = max_record[d[2]] + 1
+        rank_dict[d[3]] = max_record[d[2]]
+    return rank_dict
+
+
+# 鑾峰彇娑ㄥ仠淇℃伅
+def get_limit_up_info(codes):
+    limit_up_data = __kplDataManager.get_data(KPLDataType.LIMIT_UP)
+    limit_up_codes = set([val[0] for val in limit_up_data])
+    open_limit_up_data = __kplDataManager.get_data(KPLDataType.OPEN_LIMIT_UP)
+    open_limit_up_codes = set()
+    if open_limit_up_data:
+        open_limit_up_codes = set([val[0] for val in open_limit_up_data])
+    dict_ = {}
+    for code in codes:
+        dict_[code] = (code in limit_up_codes, code in open_limit_up_codes)
+    return dict_, limit_up_codes, open_limit_up_codes
+
+
+# 鑾峰彇浠g爜鍒嗘暟瀛楀吀
+def get_codes_scores_dict(codes):
+    # 鑾峰彇鎵�鏈夌洃鍚腑鐨勪唬鐮�
+    first_codes = gpcode_manager.get_first_gp_codes()
+    scores = {}
+    for code in codes:
+        if code not in first_codes:
+            continue
+        if code not in scores:
+            # 鑾峰彇鍒嗘暟
+            try:
+                limit_up_time = limit_up_time_manager.get_limit_up_time(code)
+                volume_rate, volume_info = code_volumn_manager.get_volume_rate(code, True)
+                (score, score_list), score_source_list = first_code_score_manager.get_score(code, volume_rate,
+                                                                                            limit_up_time,
+                                                                                            True)
+                scores[code] = score
+            except:
+                pass
+    return scores
+
+
+if __name__ == "__main__":
+    get_limit_up_info()
diff --git a/output/output_util.py b/output/output_util.py
new file mode 100644
index 0000000..543c788
--- /dev/null
+++ b/output/output_util.py
@@ -0,0 +1,14 @@
+import time
+
+
+def money_desc(money):
+    if money > 100000000:
+        return f"{round(money / 100000000, 2)}浜�"
+    else:
+        return f"{round(money / 10000, 2)}涓�"
+
+
+def time_format(timestamp):
+    if timestamp:
+        return time.strftime("%H:%M:%S", time.localtime(int(timestamp)))
+    return ""
diff --git a/server.py b/server.py
index 1b5032b..34cd254 100644
--- a/server.py
+++ b/server.py
@@ -32,7 +32,9 @@
 import ths_util
 import tool
 from output import code_info_output
-from third_data import hot_block_data_process, block_info
+from third_data import hot_block_data_process, block_info, kpl_api, kpl_util
+from third_data.code_plate_key_manager import TargetCodePlateKeyManager
+from third_data.kpl_data_manager import KPLCodeLimitUpReasonManager, KPLLimitUpDataRecordManager
 from ths import l2_listen_pos_health_manager
 from trade import trade_gui, trade_data_manager, trade_manager, l2_trade_util, deal_big_money_manager, \
     first_code_score_manager, current_price_process_manager
@@ -74,6 +76,8 @@
     first_tick_datas = []
     latest_oringin_data = {}
     last_l2_listen_health_time = {}
+    __KPLCodeLimitUpReasonManager = KPLCodeLimitUpReasonManager()
+    __TargetCodePlateKeyManager = TargetCodePlateKeyManager()
 
     def setup(self):
         super().setup()  # 鍙互涓嶈皟鐢ㄧ埗绫荤殑setup()鏂规硶锛岀埗绫荤殑setup鏂规硶浠�涔堥兘娌″仛
@@ -293,6 +297,21 @@
                             if gpcode_manager.get_limit_up_price(code) is None:
                                 juejin.re_set_price_pres([code], True)
 
+                        # 鏉垮潡鍏抽敭瀛楀噯澶�
+                        for code in codes:
+                            if self.__TargetCodePlateKeyManager.get_history_limit_up_reason(code) is None:
+                                self.__TargetCodePlateKeyManager.set_history_limit_up_reason(code,
+                                                                                             KPLLimitUpDataRecordManager.get_latest_blocks_set(
+                                                                                                 code))
+                            if self.__TargetCodePlateKeyManager.get_blocks(code) is None:
+                                try:
+                                    results = kpl_api.getStockIDPlate(code)
+                                    bs = [r[1] for r in results]
+                                    self.__TargetCodePlateKeyManager.set_blocks(code, bs)
+                                except Exception as e:
+                                    logging.exception(e)
+                                    pass
+
                         # 鑾峰彇60澶╂渶澶ц褰�
                         for code in codes:
                             need_get_volumn = False
@@ -399,6 +418,9 @@
                                 # 鍔犲叆棣栨澘娑ㄥ仠
                                 gpcode_manager.FirstCodeManager.add_limited_up_record([code])
                             pricePre = gpcode_manager.get_price_pre(code)
+                            if pricePre is None:
+                                juejin.re_set_price_pres([code])
+
                             rate = round((float(price) - pricePre) * 100 / pricePre, 1)
                             prices.append(
                                 {"code": code, "time": limit_up_time, "rate": rate,
@@ -722,7 +744,7 @@
                     __start_time = time.time()
                     final_data = {'code': code, 'data': code_info_output.get_output_html(code)}
                     return_str = json.dumps({"code": 0, "data": final_data})
-                    print("浠g爜淇℃伅鑾峰彇鏃堕棿",code,round((time.time()-__start_time)*1000))
+                    print("浠g爜淇℃伅鑾峰彇鏃堕棿", code, round((time.time() - __start_time) * 1000))
                     pass
                 # 鑾峰彇鏈�杩�2涓氦鏄撴棩娑ㄥ仠浠g爜
                 elif type == 72:
@@ -831,6 +853,11 @@
                             results = juejin.JueJinManager.get_gp_codes_names([code])
                             if results:
                                 gpcode_manager.CodesNameManager.add_first_code_name(code, results[code])
+                    if "plates" in data["data"]:
+                        for i in range(len(data["data"]["plates"])):
+                            self.__KPLCodeLimitUpReasonManager.save_reason(codes[i], data["data"]["plates"][i])
+
+                    return_str = json.dumps({"code": 0})
                 elif type == 402:
                     data = json.loads(_str)
                     codes = data["data"]["codes"]
@@ -838,11 +865,25 @@
                         gpcode_manager.WantBuyCodesManager.remove_code(code)
                     return_str = json.dumps({"code": 0})
                 elif type == 403:
+                    plate = None
+                    include_codes = set()
+                    if _str:
+                        data = json.loads(_str)
+                        plate = data.get("plate")
+                        if plate:
+                            code_map = self.__KPLCodeLimitUpReasonManager.list_all()
+                            for k in code_map:
+                                if code_map[k] == plate:
+                                    include_codes.add(k)
+
                     codes = gpcode_manager.WantBuyCodesManager.list_code()
                     datas = []
                     for code in codes:
+                        if plate and plate != '鍏朵粬' and code not in include_codes:
+                            continue
                         name = gpcode_manager.get_code_name(code)
                         datas.append(f"{name}:{code}")
+
                     return_str = json.dumps({"code": 0, "data": datas})
                 elif type == 501:
                     data = json.loads(_str)
@@ -855,6 +896,12 @@
                 elif type == 502:
                     can_buy = trade_manager.TradeStateManager.is_can_buy()
                     return_str = json.dumps({"code": 0, "data": {"can_buy": can_buy}})
+                elif type == 601:
+                    pass
+                    # 鍔犺嚜閫�
+                elif type == 602:
+                    pass
+                    # 绉婚櫎鑷��
 
                 sk.send(return_str.encode())
 
diff --git a/third_data/block_info.py b/third_data/block_info.py
index f9f2c11..9b2dc17 100644
--- a/third_data/block_info.py
+++ b/third_data/block_info.py
@@ -3,6 +3,7 @@
 """
 import datetime
 
+import constant
 import juejin
 import tool
 from third_data import kpl_util, kpl_data_manager
@@ -34,7 +35,7 @@
     for data in limit_up_datas:
         if data[0] == code:
             block = data[5]
-            if block in kpl_data_manager.INVALID_BLOCKS and filter:
+            if block in constant.KPL_INVALID_BLOCKS and filter:
                 continue
             blocks.append(block)
     return blocks
@@ -73,7 +74,7 @@
     return blocks
 
 
-def get_target_block(code, filter=False):
+def get_target_block_info(code, filter=False):
     latest_datas = __kplDataManager.get_data(kpl_util.KPLDataType.LIMIT_UP)
     blocks = __get_blocks(code, latest_datas, filter)
     if not blocks:
@@ -82,7 +83,7 @@
     target_block = None
     if blocks:
         for block in blocks:
-            if block in kpl_data_manager.INVALID_BLOCKS and filter:
+            if block in constant.KPL_INVALID_BLOCKS and filter:
                 continue
             target_block = block
             break
@@ -104,7 +105,7 @@
     target_block = None
     if blocks:
         for block in blocks:
-            if block in kpl_data_manager.INVALID_BLOCKS:
+            if block in constant.KPL_INVALID_BLOCKS:
                 continue
             target_block = block
             break
@@ -139,7 +140,7 @@
     # 鏄惁鍑虹幇杩囬珮浣嶆澘
     high_block_infos = []
     for block in blocks:
-        if block in kpl_data_manager.INVALID_BLOCKS:
+        if block in constant.KPL_INVALID_BLOCKS:
             continue
         if latest_datas:
             has_high, high_code_info = __is_has_high_code(block, latest_datas)
@@ -183,12 +184,13 @@
     re_limit_codes = set()
     # 鐐告澘锛�
     # (浠g爜,鍚嶇О,娑ㄥ箙,鏉垮潡,瀹為檯娴侀��)
-    for data in open_limit_up_datas:
-        blocks = set(data[3].split("銆�"))
-        if target_block not in blocks:
-            continue
-        code_ = data[0]
-        break_codes.add(code_)
+    if open_limit_up_datas:
+        for data in open_limit_up_datas:
+            blocks = set(data[3].split("銆�"))
+            if target_block not in blocks:
+                continue
+            code_ = data[0]
+            break_codes.add(code_)
     # 缁熻鍥炲皝
     for data in latest_datas:
         if data[5] != target_block:
diff --git a/third_data/code_plate_key_manager.py b/third_data/code_plate_key_manager.py
new file mode 100644
index 0000000..4a13787
--- /dev/null
+++ b/third_data/code_plate_key_manager.py
@@ -0,0 +1,240 @@
+"""
+浠g爜琛屼笟鍏抽敭璇嶇鐞�
+"""
+
+# 娑ㄥ仠浠g爜鍏抽敭璇嶆澘鍧楃鐞�
+import json
+
+import constant
+import global_data_loader
+import global_util
+import log
+import tool
+from db import redis_manager
+
+from log import logger_kpl_limit_up
+from trade import trade_manager
+
+
+# 瀹炴椂寮�鐩樺暒甯傚満鏁版嵁
+class RealTimeKplMarketData:
+    # 绮鹃�夊墠5
+    top_5_reason_set = set()
+    # 琛屼笟鍓�5
+    top_5_industry_set = set()
+
+    @classmethod
+    def set_top_5_reasons(cls, datas):
+        temp_set = set()
+        base_count = 5
+        for i in range(0, len(datas)):
+            if datas[i][1] in constant.KPL_INVALID_BLOCKS:
+                base_count += 1
+            if i >= base_count:
+                break
+            if datas[i][3] > 5000 * 10000:
+                temp_set.add(datas[i][1])
+        cls.top_5_reason_set = temp_set
+
+    @classmethod
+    def set_top_5_industry(cls, datas):
+        temp_set = set()
+        base_count = 5
+        for i in range(0, len(datas)):
+            if datas[i][1] in constant.KPL_INVALID_BLOCKS:
+                base_count += 1
+            if i >= base_count:
+                break
+
+            if datas[i][2] > 5000 * 10000:
+                temp_set.add(datas[i][1])
+        cls.top_5_reason_set = temp_set
+
+    # 鑾峰彇鑳藉涔扮殑琛屼笟鍏抽敭瀛梥et
+    @classmethod
+    def get_can_buy_key_set(cls):
+        temp_set = cls.top_5_reason_set | cls.top_5_industry_set
+        return temp_set
+
+    @classmethod
+    def is_in_top(cls, keys):
+        reasons = cls.get_can_buy_key_set()
+        temp_set = keys & reasons
+        if temp_set:
+            return True, temp_set
+        else:
+            return False, None
+
+
+class LimitUpCodesPlateKeyManager:
+    # 浠婃棩娑ㄥ仠鍘熷洜
+    today_limit_up_reason_dict = {}
+    today_total_limit_up_reason_dict = {}
+    total_code_keys_dict = {}
+    total_key_codes_dict = {}
+    __redisManager = redis_manager.RedisManager(1)
+
+    def __get_redis(self):
+        return self.__redisManager.getRedis()
+
+    # 鑾峰彇浠婃棩娑ㄥ仠鏁版嵁锛屾牸寮忥細[(浠g爜,娑ㄥ仠鍘熷洜)]
+    def set_today_limit_up(self, datas):
+        temp_dict = {}
+        if datas:
+            for item in datas:
+                temp_dict[item[0]] = item[1]
+            self.today_limit_up_reason_dict = temp_dict
+        if datas:
+            for item in datas:
+                self.__set_total_keys(item[0])
+        self.set_today_total_limit_up(datas)
+
+    # 璁剧疆浠婃棩鍘嗗彶娑ㄥ仠鏁版嵁
+    def set_today_total_limit_up(self, datas):
+        for item in datas:
+            code = item[0]
+            self.today_total_limit_up_reason_dict[code] = item[1]
+
+    # 浠婃棩娑ㄥ仠鍘熷洜鍙樺寲
+    def set_today_limit_up_reason_change(self, code, from_reason, to_reason):
+        self.__get_redis().sadd(f"kpl_limit_up_reason_his-{code}", from_reason)
+        self.__get_redis().expire(f"kpl_limit_up_reason_his-{code}", tool.get_expire())
+        self.__set_total_keys(code)
+
+    def __set_total_keys(self, code):
+        keys = set()
+        keys_his = self.__get_redis().smembers(f"kpl_limit_up_reason_his-{code}")
+        keys |= keys_his
+        if code in self.today_limit_up_reason_dict:
+            keys.add(self.today_limit_up_reason_dict.get(code))
+        self.total_code_keys_dict[code] = keys
+        for k in keys:
+            if k not in self.total_key_codes_dict:
+                self.total_key_codes_dict[k] = set()
+            self.total_key_codes_dict[k].add(code)
+
+        logger_kpl_limit_up.info("{}鏉垮潡鍏抽敭璇�:{}", code, keys)
+
+    def get_codes_by_key_without_mine(self, key, code):
+        # 鍙瘮杈冧粖鏃ユ定鍋滃師鍥�
+        codes_set = set()
+        if key in self.total_key_codes_dict:
+            codes_set |= self.total_key_codes_dict[key]
+        codes_set.discard(code)
+        return codes_set
+
+
+# 鐩爣浠g爜鍏抽敭璇嶇鐞�
+class TargetCodePlateKeyManager:
+    __redisManager = redis_manager.RedisManager(1)
+    # 鍘嗗彶娑ㄥ仠鍘熷洜
+    __history_limit_up_reason_dict = {}
+    # 浜岀骇琛屼笟
+    __second_industry_dict = {}
+    # 鏉垮潡
+    __blocks_dict = {}
+
+    def __get_redis(self):
+        return self.__redisManager.getRedis()
+
+    def set_history_limit_up_reason(self, code, reasons):
+        self.__history_limit_up_reason_dict[code] = set(reasons)
+        self.__get_redis().setex(f"kpl_his_limit_up_reason-{code}", tool.get_expire(), json.dumps(list(reasons)))
+
+    # 濡傛灉杩斿洖鍊间笉涓篘one琛ㄧず宸茬粡鍔犺浇杩囧巻鍙插師鍥犱簡
+    def get_history_limit_up_reason(self, code):
+        reasons = self.__history_limit_up_reason_dict.get(code)
+        if reasons is None:
+            # 浠庡唴瀛樹腑鍔犺浇
+            val = self.__get_redis().get(f"kpl_his_limit_up_reason-{code}")
+            if val is not None:
+                val = set(json.loads(val))
+                self.__history_limit_up_reason_dict[code] = val
+            return self.__history_limit_up_reason_dict.get(code)
+        else:
+            return reasons
+
+    def set_blocks(self, code, blocks):
+        self.__blocks_dict[code] = set(blocks)
+        self.__get_redis().setex(f"kpl_blocks-{code}", tool.get_expire(), json.dumps(list(blocks)))
+
+    def get_blocks(self, code):
+        reasons = self.__blocks_dict.get(code)
+        if reasons is None:
+            # 浠庡唴瀛樹腑鍔犺浇
+            val = self.__get_redis().get(f"kpl_blocks-{code}")
+            if val is not None:
+                val = set(json.loads(val))
+                self.__blocks_dict[code] = val
+            return self.__blocks_dict.get(code)
+        else:
+            return reasons
+
+    # 杩斿洖key闆嗗悎(鎺掗櫎鏃犳晥鏉垮潡),浠婃棩娑ㄥ仠鍘熷洜,浠婃棩鍘嗗彶娑ㄥ仠鍘熷洜,鍘嗗彶娑ㄥ仠鍘熷洜,浜岀骇,鏉垮潡
+    def get_plate_keys(self, code):
+        keys = set()
+        k1 = set()
+        if code in LimitUpCodesPlateKeyManager.today_total_limit_up_reason_dict:
+            k1 = {LimitUpCodesPlateKeyManager.today_total_limit_up_reason_dict[code]}
+        # 鍔犺浇鍘嗗彶鍘熷洜
+        k11 = self.__get_redis().smembers(f"kpl_limit_up_reason_his-{code}")
+        k2 = set()
+        if code in self.__history_limit_up_reason_dict:
+            k2 = self.__history_limit_up_reason_dict[code]
+        k3 = set()
+        industry = global_util.code_industry_map.get(code)
+        if industry:
+            k3 = {industry}
+
+        k4 = set()
+        if code in self.__blocks_dict:
+            k4 = self.__blocks_dict[code]
+        for k in [k1, k11, k2, k3, k4]:
+            keys |= k
+
+        # 鎺掗櫎鏃犳晥鐨勬定鍋滃師鍥�
+        keys = keys - set(constant.KPL_INVALID_BLOCKS)
+
+        return keys, k1, k11, k2, k3, k4
+
+
+class CodePlateKeyBuyManager:
+    __TargetCodePlateKeyManager = TargetCodePlateKeyManager()
+    __LimitUpCodesPlateKeyManager = LimitUpCodesPlateKeyManager()
+
+    # 鏄惁鍙互涓嬪崟
+    @classmethod
+    def can_buy(cls, code):
+        keys, k1, k11, k2, k3, k4 = cls.__TargetCodePlateKeyManager.get_plate_keys(code)
+        # 鏉垮潡Key鏄惁鍦ㄥ競鍦哄墠5key涓�
+        is_in, valid_keys = RealTimeKplMarketData.is_in_top(keys)
+        if not valid_keys:
+            return False, "鏉垮潡鏈湪甯傚満娴佸叆鍓�5"
+        # 鐩稿悓鏉垮潡涓槸鍚﹀凡缁忔湁鍒殑绁ㄦ定鍋�
+        is_back = False, ''
+        for key in valid_keys:
+            codes = cls.__LimitUpCodesPlateKeyManager.get_codes_by_key_without_mine(key, code)
+            if codes and len(codes) > 0:
+                is_back = True, key
+                break
+        if not is_back[0]:
+            return False, f"鏉垮潡涓涓定鍋滐細{valid_keys}"
+        # 鐪嬫澘鍧椾腑鏄惁宸茬粡鏈夊凡缁忎笅鍗曠殑鎴栬�呮垚浜ょ殑浠g爜
+        codes = trade_manager.get_codes_by_trade_states(
+            {trade_manager.TRADE_STATE_BUY_DELEGATED, trade_manager.TRADE_STATE_BUY_PLACE_ORDER,
+             trade_manager.TRADE_STATE_BUY_SUCCESS})
+        # 閬嶅巻宸茬粡鎴愪氦/涓嬪崟鐨勪唬鐮侊紝鑾峰彇鍏舵定鍋滃師鍥狅紝鐒跺悗鍜屽綋鍓嶄唬鐮佹定鍋滃師鍥犲仛姣旇緝锛屾湁鐩稿悓浠g爜鐨勪笉鑳戒拱
+        for c in codes:
+            keys_, k1_, k11_, k2_, k3_, k4_ = cls.__TargetCodePlateKeyManager.get_plate_keys(c)
+            # 瀹炴椂娑ㄥ仠鍘熷洜
+            for k_ in k1_:
+                # 褰撳墠浠g爜宸茬粡鏈夋寕鐨勬垨鑰呮垚浜ょ殑
+                if k_ in valid_keys:
+                    return False, f"{k_}鏉垮潡涓殑{c}宸茬粡涓嬪崟/涔板叆鎴愬姛锛屽悓涓�鏉垮潡涓彧鑳戒拱1涓エ"
+        return True, f"娑ㄥ仠鍘熷洜锛歿is_back[1]}"
+
+
+if __name__ == "__main__":
+    datas = log.load_kpl_reason_changes()
+    for k in datas:
+        LimitUpCodesPlateKeyManager().set_today_limit_up_reason_change(k[0], k[1], k[2])
diff --git a/third_data/data_server.py b/third_data/data_server.py
index e8665f2..b1fa9a3 100644
--- a/third_data/data_server.py
+++ b/third_data/data_server.py
@@ -5,20 +5,229 @@
 import time
 from http.server import BaseHTTPRequestHandler
 import cv2
+import dask
 
+import global_util
+import gpcode_manager
+import log
 import tool
 from l2 import code_price_manager
-from third_data import kpl_util, kpl_data_manager
-from third_data.kpl_data_manager import KPLDataManager
+from output.limit_up_data_filter import IgnoreCodeManager
+from third_data import kpl_util, kpl_data_manager, kpl_api
+from third_data.code_plate_key_manager import RealTimeKplMarketData
+from third_data.kpl_data_manager import KPLDataManager, KPLLimitUpDataRecordManager, KPLPlatManager, \
+    KPLCodeLimitUpReasonManager
 from third_data.kpl_util import KPLDataType
 import urllib.parse as urlparse
+from urllib.parse import parse_qs
+from output import code_info_output, limit_up_data_filter, output_util
 
-from trade import bidding_money_manager
+from trade import bidding_money_manager, trade_manager
+from trade.l2_trade_util import BlackListCodeManager
 
 
 class DataServer(BaseHTTPRequestHandler):
     ocr_temp_data = {}
     __kplDataManager = KPLDataManager()
+    __IgnoreCodeManager = IgnoreCodeManager()
+    __KPLPlatManager = KPLPlatManager()
+    __KPLCodeLimitUpReasonManager = KPLCodeLimitUpReasonManager()
+    # 鍘嗗彶鏉垮潡
+    __history_plates_dict = {}
+    # 鏉垮潡
+    __blocks_dict = {}
+
+    def __get_limit_up_list(self):
+        # 缁熻鐩墠涓烘鐨勪唬鐮佹定鍋滄暟閲忥紙鍒嗘定鍋滃師鍥狅級
+        now_limit_up_codes_info = self.__kplDataManager.get_data(KPLDataType.LIMIT_UP)
+        limit_up_reason_dict = {}
+        for d in now_limit_up_codes_info:
+            if d[5] not in limit_up_reason_dict:
+                limit_up_reason_dict[d[5]] = [0, 0]
+            limit_up_reason_dict[d[5]][0] += 1
+        # 鑾峰彇鎯充拱鍘熷洜鎯充拱鍗曠殑浠g爜鏁伴噺
+        reason_map = self.__KPLCodeLimitUpReasonManager.list_all()
+        want_codes = gpcode_manager.WantBuyCodesManager.list_code()
+        # 鍏朵粬鎯充拱鍗�
+        other_count = 0
+        for k in reason_map:
+            reson = reason_map[k]
+            if k in want_codes and reson in limit_up_reason_dict:
+                limit_up_reason_dict[reson][1] += 1
+            elif k in want_codes:
+                other_count += 1
+
+        limit_up_reason_statistic_info = [(k, limit_up_reason_dict[k][0], limit_up_reason_dict[k][1]) for k in
+                                          limit_up_reason_dict]
+        limit_up_reason_statistic_info.sort(key=lambda x: x[1])
+        limit_up_reason_statistic_info.reverse()
+        if other_count > 0:
+            limit_up_reason_statistic_info.insert(0, ('鍏朵粬', other_count, other_count))
+
+        total_datas = KPLLimitUpDataRecordManager.total_datas
+        if not total_datas:
+            KPLLimitUpDataRecordManager.load_total_datas()
+            total_datas = KPLLimitUpDataRecordManager.total_datas
+        # 閫氳繃娑ㄥ仠鏃堕棿鎺掑簭
+        total_datas = list(total_datas)
+
+        codes_set = set([d[3] for d in total_datas])
+        # 鍒ゆ柇鏄緳鍑狅紝鍒ゆ柇鏄惁娑ㄥ仠锛屽垽鏂槸鍚︾偢鏉匡紝鍔犺浇鍒嗘暟
+        rank_dict = limit_up_data_filter.get_limit_up_time_rank_dict(total_datas)
+        limit_up_dict, limit_up_codes, open_limit_up_codes = limit_up_data_filter.get_limit_up_info(codes_set)
+        score_dict = limit_up_data_filter.get_codes_scores_dict(codes_set)
+        fresult = []
+        ignore_codes = self.__IgnoreCodeManager.list_ignore_codes("1")
+
+        total_datas.sort(key=lambda x: int(x[5]))
+        total_datas.reverse()
+
+        # 鑾峰彇娑ㄥ仠鍘熷洜鍙樺寲璁板綍
+        reason_changes = log.load_kpl_reason_changes()
+        reason_changes.reverse()
+        reason_changes_dict = {}
+        for r in reason_changes:
+            if r[0] not in reason_changes_dict:
+                reason_changes_dict[r[0]] = r[1]
+
+        for d in total_datas:
+            code = d[3]
+            # (浠g爜, 鍚嶇О, 娑ㄥ仠鐘舵��(0 - 鏃犵姸鎬� 1-娑ㄥ仠 2-鐐告澘), 榫欏嚑, 棣栨澘, 鍒嗗��, 娑ㄥ仠鏃堕棿, 鍘熷洜, 鐩稿悓鍘熷洜浠g爜鏁伴噺, 鑷敱娴侀��, 娑ㄥ仠鍘熷洜鏄惁鍙樺寲)
+            limit_up_state = 0
+            if code in limit_up_dict:
+                if limit_up_dict[code][0]:
+                    limit_up_state = 1
+                elif limit_up_dict[code][1]:
+                    limit_up_state = 2
+            score = ""
+            if code in score_dict:
+                score = score_dict[code]
+            if code in ignore_codes:
+                continue
+            fresult.append((code, d[4], limit_up_state, f"榫檣rank_dict.get(code)}", d[12], score,
+                            output_util.time_format(int(d[5])), d[2], d[10], output_util.money_desc(d[13]),
+                            reason_changes_dict.get(code)))
+        response_data = json.dumps({"code": 0, "data": {"limit_up_count": len(limit_up_codes),
+                                                        "open_limit_up_count": len(open_limit_up_codes),
+                                                        "limit_up_reason_statistic": limit_up_reason_statistic_info,
+                                                        "limit_up_codes": fresult}})
+        return response_data
+
+    def __get_plate_info(self, ps_dict):
+
+        @dask.delayed
+        def kpl_getStockIDPlate(code_):
+            temp_data = kpl_api.getStockIDPlate(code_)
+            return temp_data
+
+        @dask.delayed
+        def kpl_getSonPlate(plate_code_):
+            if not plate_code:
+                return None
+            temp_data = kpl_api.getSonPlate(plate_code_)
+            return temp_data
+
+        @dask.delayed
+        def kpl_getCodesByPlate(plate_code_):
+            if not plate_code:
+                return None
+            temp_data = kpl_api.getCodesByPlate(plate_code_)
+            return temp_data
+
+        @dask.delayed
+        def request_data(f1_, f2_):
+            temp_data = f1_, f2_
+            return temp_data
+
+        # 鑾峰彇鏉垮潡鐨勪唬鐮�
+        fresult = {}
+        code = ps_dict["code"]
+        code_info = KPLLimitUpDataRecordManager.list_by_code(code, tool.get_now_date_str())[0]
+        hot_block_name = code_info[2]
+        plate_code = self.__KPLPlatManager.get_plat(hot_block_name)
+        f1 = kpl_getStockIDPlate(code)
+        # f2 = kpl_getSonPlate(plate_code)
+        f3 = kpl_getCodesByPlate(plate_code)
+        dask_result = request_data(f1, f3)
+        plate_info, codes_by_plate_info = dask_result.compute()
+
+        if plate_info:
+            plate_info.sort(key=lambda x: x[2])
+            plate_info.reverse()
+            fresult["plate"] = plate_info
+
+        # 鑾峰彇浠g爜鐨勫巻鍙叉定鍋滄暟鎹�,(娑ㄥ仠鍘熷洜,鏃ユ湡,鏉垮潡)
+        fresult["code_records"] = KPLLimitUpDataRecordManager.get_latest_infos(code, 4, False)[:2]
+        # 鑾峰彇浠婃棩鏁版嵁
+        fresult["today"] = (code_info[2], code_info[1], code_info[6])
+        fresult["industry"] = global_util.code_industry_map.get(code)
+        if plate_code:
+            # 鑾峰彇寮哄害
+            # datas = son_plate_info
+            # # (浠g爜,鍚嶇О,寮哄害)
+            # temp = kpl_util.parseSonPlat(datas)
+            # temp.sort(key=lambda x: x[2])
+            # temp.reverse()
+            # fresult["plat_strength"] = temp
+
+            # 鑾峰彇娑ㄥ仠鍘熷洜涓嬮潰鐨勫垪琛�
+            datas = codes_by_plate_info
+            # (浠g爜,鍚嶇О,鐜颁环,娑ㄥ箙,鑷敱娴侀��,鍑犳澘锛岄緳鍑狅紝涓诲姏鍑�棰�,300w鍑�棰�,鏈烘瀯澧炰粨)
+            temps = kpl_util.parsePlateCodes(datas)
+            # --鏁版嵁鍑嗗寮�濮�--
+            codes_set = set([d[0] for d in temps])
+            limit_up_dict, limit_up_codes, open_limit_up_codes = limit_up_data_filter.get_limit_up_info(codes_set)
+            score_dict = limit_up_data_filter.get_codes_scores_dict(codes_set)
+            want_codes = gpcode_manager.WantBuyCodesManager.list_code()
+            black_codes = BlackListCodeManager.list_codes()
+            total_datas = KPLLimitUpDataRecordManager.total_datas
+            code_info_dict = {}
+            for val in total_datas:
+                code_info_dict[val[3]] = val
+
+            # --鏁版嵁鍑嗗缁撴潫--
+
+            ignore_codes = self.__IgnoreCodeManager.list_ignore_codes("2")
+            # 鏈�缁堢粨鏋滐細(浠g爜,鍚嶇О,娑ㄥ仠鐘舵��(0-鏃犵姸鎬� 1-娑ㄥ仠 2-鐐告澘),榫欏嚑,棣栨澘,鍒嗗��,娑ㄥ仠鏃堕棿,鍘熷洜,鐩稿悓鍘熷洜浠g爜鏁伴噺,鑷敱娴侀��,娑ㄥ仠鍘熷洜鏄惁鍙樺寲,娑ㄥ箙,鐜颁环,榛戝悕鍗�,鎯充拱鍗�,涓诲姏鍑�鍊�,300w,)
+            codes_info_list = []
+            for t in temps:
+                code = t[0]
+                limit_up_state = 0
+                if code in limit_up_dict:
+                    if limit_up_dict[code][0]:
+                        limit_up_state = 1
+                    elif limit_up_dict[code][1]:
+                        limit_up_state = 2
+                score = ""
+                if code in score_dict:
+                    score = score_dict[code]
+
+                limit_up_time = ''
+                if code in code_info_dict:
+                    limit_up_time = output_util.time_format(code_info_dict[code][5])
+                final_code_info = {"code_info": (
+                    t[0], t[1], limit_up_state, t[6], t[5], score, limit_up_time,
+                    code_info[2], code_info[10], output_util.money_desc(t[4]), 0, t[3], t[2],
+                    "榛戝悕鍗�" if code in black_codes else "", "鎯充拱鍗�" if code in want_codes else "",
+                    output_util.money_desc(t[7]), output_util.money_desc(t[8]), output_util.money_desc(t[9]))}
+                if code in code_info_dict:
+                    final_code_info["today"] = (
+                        code_info_dict[code][2], code_info_dict[code][1], code_info_dict[code][6])
+                # 鍔犺浇鍘嗗彶
+                if code in self.__history_plates_dict:
+                    final_code_info["code_records"] = self.__history_plates_dict[code][1]
+                # 鍔犺浇鏉垮潡
+                if code in self.__blocks_dict:
+                    final_code_info["plate"] = self.__blocks_dict[code][1]
+
+                # 鑾峰彇浜岀骇琛屼笟
+                final_code_info["industry"] = global_util.code_industry_map.get(code)
+
+                if code not in ignore_codes:
+                    codes_info_list.append(final_code_info)
+                fresult["code_list_info"] = codes_info_list
+        response_data = json.dumps({"code": 0, "data": fresult})
+        return response_data
 
     def do_GET(self):
         path = self.path
@@ -26,7 +235,7 @@
         response_data = ""
         if url.path == "/get_kpl_data":
             best_feng_kou = self.__kplDataManager.get_data(kpl_util.KPLDataType.BEST_FENG_KOU)
-            best_feng_kou=best_feng_kou[:22]
+            best_feng_kou = best_feng_kou[:22]
             feng_kou = self.__kplDataManager.get_data(kpl_util.KPLDataType.FENG_KOU)
             feng_kou = feng_kou[:22]
             industry_rank = self.__kplDataManager.get_data(kpl_util.KPLDataType.INDUSTRY_RANK)
@@ -35,6 +244,58 @@
             feng_xiang = feng_xiang[:22]
             response_data = json.dumps({"code": 0, "data": {"best_feng_kou": best_feng_kou, "feng_kou": feng_kou,
                                                             "industry_rank": industry_rank, "feng_xiang": feng_xiang}})
+        elif url.path == "/get_score_info":
+            ps_dict = dict([(k, v[0]) for k, v in parse_qs(url.query).items()])
+            code = ps_dict['code']
+            name = ps_dict.get('name')
+
+            data = code_info_output.get_output_params(code)
+            if data["code_name"].find("None") > -1 and name:
+                data["code_name"] = f"{name} {code}"
+
+            self.__history_plates_dict[code] = (time.time(), data["kpl_code_info"]["code_records"])
+            self.__blocks_dict[code] = (time.time(), data["kpl_code_info"]["plate"])
+
+            response_data = json.dumps({"code": 0, "data": data})
+            # 鑾峰彇璇勫垎淇℃伅
+            pass
+        elif url.path == "/kpl/get_limit_up_list":
+            response_data = self.__get_limit_up_list()
+
+        elif url.path == "/kpl/get_plate_info":
+            ps_dict = dict([(k, v[0]) for k, v in parse_qs(url.query).items()])
+            response_data = self.__get_plate_info(ps_dict)
+
+        elif url.path == "/kpl/get_market_data":
+            # 鑾峰彇鏉垮潡淇℃伅
+            ps_dict = dict([(k, v[0]) for k, v in parse_qs(url.query).items()])
+            type_ = int(ps_dict['type'])
+            result = []
+            if type_ == 0:
+                # 琛屼笟锛屼富鍔涘噣棰濆�掑簭
+                result = kpl_api.getMarketIndustryRealRankingInfo(True)
+                result = kpl_util.parseMarketIndustry(result)
+            elif type_ == 1:
+                # 琛屼笟锛屼富鍔涘噣棰濋『搴�
+                result = kpl_api.getMarketIndustryRealRankingInfo(False)
+                result = kpl_util.parseMarketIndustry(result)
+            elif type_ == 2:
+                # 绮鹃�夛紝涓诲姏鍑�棰濆�掑簭
+                result = kpl_api.getMarketJingXuanRealRankingInfo(True)
+                result = kpl_util.parseMarketJingXuan(result)
+            elif type_ == 3:
+                # 绮鹃�夛紝涓诲姏鍑�棰濋『搴�
+                result = kpl_api.getMarketJingXuanRealRankingInfo(False)
+                result = kpl_util.parseMarketJingXuan(result)
+
+            response_data = json.dumps({"code": 0, "data": result})
+        elif url.path == "/kpl/add_ignore_code":
+            ps_dict = dict([(k, v[0]) for k, v in parse_qs(url.query).items()])
+            code = ps_dict['code']
+            type_ = ps_dict['type']
+            self.__IgnoreCodeManager.ignore_code(type_, code)
+            response_data = json.dumps({"code": 0})
+
         self.send_response(200)
         # 鍙戠粰璇锋眰瀹㈡埛绔殑鍝嶅簲鏁版嵁
         self.send_header('Content-type', 'application/json')
@@ -54,7 +315,7 @@
         type_ = data["type"]
         print("寮�鐩樺暒type:", type_)
         if type_ == KPLDataType.BIDDING.value:
-            result_list = kpl_util.parseDaBanData(data["data"], kpl_util.DABAN_TYPE_LIMIT_UP)
+            result_list = kpl_util.parseDaBanData(data["data"], kpl_util.DABAN_TYPE_BIDDING)
             # 绔炰环鍙栧墠20
             if result_list:
                 result_list.sort(key=lambda x: x[2])
@@ -107,9 +368,16 @@
                 self.__kplDataManager.save_data(type_, result_list)
         elif type_ == KPLDataType.INDUSTRY_RANK.value:
             result_list = kpl_util.parseIndustryRank(data["data"])
-            # 淇濆瓨椋庡悜鏁版嵁
+            # 淇濆瓨琛屼笟鏁版嵁
             if result_list:
                 self.__kplDataManager.save_data(type_, result_list)
+                RealTimeKplMarketData.set_top_5_industry(result_list)
+        elif type_ == KPLDataType.JINGXUAN_RANK.value:
+            result_list = kpl_util.parseMarketJingXuan(data["data"])
+            # 淇濆瓨绮鹃�夋暟鎹�
+            if result_list:
+                self.__kplDataManager.save_data(type_, result_list)
+                RealTimeKplMarketData.set_top_5_reasons(result_list)
         return json.dumps({"code": 0})
 
     def __send_response(self, data):
diff --git a/third_data/kpl_api.py b/third_data/kpl_api.py
index 7bc9e76..ea86177 100644
--- a/third_data/kpl_api.py
+++ b/third_data/kpl_api.py
@@ -26,3 +26,42 @@
     if int(result["errcode"]) != 0:
         return None
     return result["ListJX"]
+
+# 鑾峰彇姒傚康浠g爜
+def getCodesByPlate(plate_code):
+    data = f"Order=1&a=ZhiShuStockList_W8&st=30&c=ZhiShuRanking&PhoneOSNew=1&old=1&DeviceID=a38adabd-99ef-3116-8bb9-6d893c846e23&VerSion=5.8.0.2&IsZZ=0&Token=0&Index=0&apiv=w32&Type=6&IsKZZType=0&UserID=0&PlateID={plate_code}&"
+    response = __base_request("https://apphq.longhuvip.com/w1/api/index.php",
+                              data=data)
+    if response.status_code != 200:
+        raise Exception("璇锋眰鍑洪敊")
+    return response.text
+
+
+# 鑾峰彇姒傚康涓殑鏉垮潡寮哄害
+def getSonPlate(plate_code):
+    data = f"a=SonPlate_Info&apiv=w32&c=ZhiShuRanking&PhoneOSNew=1&DeviceID=a38adabd-99ef-3116-8bb9-6d893c846e23&VerSion=5.8.0.2&PlateID={plate_code}&"
+    response = __base_request("https://apphq.longhuvip.com/w1/api/index.php", data=data)
+    if response.status_code != 200:
+        raise Exception("璇锋眰鍑洪敊")
+    return response.text
+
+
+# 甯傚満琛屾儏-琛屼笟
+def getMarketIndustryRealRankingInfo(orderJingE_DESC=True):
+    data = f"Order={ 1 if orderJingE_DESC else 0}&a=RealRankingInfo&st=80&apiv=w32&Type=5&c=ZhiShuRanking&PhoneOSNew=1&DeviceID=a38adabd-99ef-3116-8bb9-6d893c846e23&VerSion=5.8.0.2&Index=0&ZSType=4&"
+    response = __base_request("https://apphq.longhuvip.com/w1/api/index.php",
+                              data=data)
+    if response.status_code != 200:
+        raise Exception("璇锋眰鍑洪敊")
+    return response.text
+
+
+# 甯傚満琛屾儏-绮鹃��
+def getMarketJingXuanRealRankingInfo(orderJingE_DESC=True):
+    data = f"Order={ 1 if orderJingE_DESC else 0}&a=RealRankingInfo&st=80&apiv=w32&Type=5&c=ZhiShuRanking&PhoneOSNew=1&DeviceID=a38adabd-99ef-3116-8bb9-6d893c846e23&VerSion=5.8.0.2&Index=0&ZSType=7&"
+    response = __base_request("https://apphq.longhuvip.com/w1/api/index.php",
+                              data=data)
+    if response.status_code != 200:
+        raise Exception("璇锋眰鍑洪敊")
+    return response.text
+
diff --git a/third_data/kpl_data_manager.py b/third_data/kpl_data_manager.py
index 27ea980..8904b81 100644
--- a/third_data/kpl_data_manager.py
+++ b/third_data/kpl_data_manager.py
@@ -5,17 +5,63 @@
 import tool
 
 # 寮�鐩樺暒鍘嗗彶娑ㄥ仠鏁版嵁绠$悊
-from db import mysql_data
+from db import mysql_data, redis_manager
 from l2 import code_price_manager
+from log import logger_kpl_limit_up_reason_change
 from third_data import kpl_util
+from third_data.code_plate_key_manager import LimitUpCodesPlateKeyManager
 
-INVALID_BLOCKS = ["涓�瀛f姤澧為暱", "浜屽鎶ュ闀�", "涓夊鎶ュ闀�", "鍥涘鎶ュ闀�", "涓氱哗澧為暱", "涓姤澧為暱", "骞存姤澧為暱", "骞存姤棰勫", "鏃�", "娆℃柊鑲�", "ST鎽樺附", "瓒呰穼", "鑲℃潈杞",
-                  "骞惰喘閲嶇粍"]
+
+# 浠g爜瀵瑰簲鐨勬定鍋滃師鍥犱繚瀛�
+class KPLCodeLimitUpReasonManager:
+    __redisManager = redis_manager.RedisManager(3)
+
+    def __get_redis(self):
+        return self.__redisManager.getRedis()
+
+    def save_reason(self, code, reason):
+        self.__get_redis().setex(f"kpl_limitup_reason-{code}", tool.get_expire(), reason)
+
+    def list_all(self):
+        keys = self.__get_redis().keys("kpl_limitup_reason-*")
+        dict_ = {}
+        for k in keys:
+            val = self.__get_redis().get(k)
+            dict_[k.split("-")[1]] = val
+        return dict_
+
+
+class KPLPlatManager:
+    def save_plat(self, _id, name):
+        if not _id:
+            return
+        mysqldb = mysql_data.Mysqldb()
+        key = f"{_id}-{name}"
+        results = mysqldb.select_one(f"select * from kpl_plate where _name='{name}'")
+        if not results:
+            mysqldb.execute(f"insert into kpl_plate(_id,_name,_key) values({_id},'{name}','{key}')")
+
+    def get_plat(self, name):
+        mysqldb = mysql_data.Mysqldb()
+        results = mysqldb.select_one(f"select * from kpl_plate where _name='{name}'")
+        if results:
+            return results[0]
+        return None
+
+    def get_same_plat_names(self, name):
+        mysqldb = mysql_data.Mysqldb()
+        plate = self.get_plat(name)
+        if not plate:
+            return {name}
+        results = mysqldb.select_all(f"select _name from kpl_plate where _id='{plate}'")
+        return set([r[0] for r in results])
 
 
 class KPLLimitUpDataRecordManager:
     total_datas = None
     latest_datas = {}
+    __kplPlatManager = KPLPlatManager()
+    __LimitUpCodesPlateKeyManager = LimitUpCodesPlateKeyManager()
 
     @classmethod
     def save_record(cls, day, records):
@@ -28,22 +74,33 @@
                 if not code_block_dict.get(code):
                     code_block_dict[code] = set()
                 code_block_dict[code].add(b)
+                # 璁剧疆娑ㄥ仠鏁版嵁
+        if records:
+            cls.__LimitUpCodesPlateKeyManager.set_today_limit_up([(r[0], r[5]) for r in records])
 
         # 娑ㄥ仠鏁版嵁璁板綍
         mysqldb = mysql_data.Mysqldb()
+        # 缁熻娑ㄥ仠鍘熷洜鍜屾蹇典唬鐮�
+        plats = {}
         for d in records:
-            # (浠g爜, 鍚嶇О, 棣栨娑ㄥ仠鏃堕棿, 鏈�杩戞定鍋滄椂闂�, 鍑犳澘, 娑ㄥ仠鍘熷洜, 鏉垮潡, 瀹為檯娴侀��, 涓诲姏鍑�棰�)
+            plats[d[5]] = d[9]
+        for p in plats:
+            cls.__kplPlatManager.save_plat(plats[p], p)
+
+        for d in records:
+            # (浠g爜, 鍚嶇О, 棣栨娑ㄥ仠鏃堕棿, 鏈�杩戞定鍋滄椂闂�, 鍑犳澘, 娑ㄥ仠鍘熷洜, 鏉垮潡, 瀹為檯娴侀��, 涓诲姏鍑�棰�,娑ㄥ仠鍘熷洜浠g爜,娑ㄥ仠鍘熷洜浠g爜鏁伴噺)
             code = d[0]
             _id = f"{day}_{code}_{d[5]}"
 
             result = mysqldb.select_one("select * from kpl_limit_up_record where _id='{}'".format(_id))
             if not result:
                 mysqldb.execute(
-                    f"insert into kpl_limit_up_record(_id,_day,_hot_block_name,_code,_code_name,_limit_up_time,_blocks,_latest_limit_up_time,_update_time,_create_time) values('{_id}','{day}','{d[5]}','{d[0]}','{d[1]}','{d[2]}','{d[6]}','{d[3]}',now(),now())")
+                    f"insert into kpl_limit_up_record(_id,_day,_hot_block_name,_code,_code_name,_limit_up_time,_blocks,_latest_limit_up_time,_update_time,_create_time,_hot_block_code_count,_limit_up_high_info,_zylt_val) values('{_id}','{day}','{d[5]}','{d[0]}','{d[1]}','{d[2]}','{d[6]}','{d[3]}',now(),now(),{d[10]},'{d[4]}',{d[7]})")
+
             else:
                 if _id in cls.latest_datas and json.dumps(cls.latest_datas.get(_id)) != json.dumps(d):
                     mysqldb.execute(
-                        f"update kpl_limit_up_record set _latest_limit_up_time='{d[3]}',_limit_up_time='{d[2]}' ,_update_time=now() where _id='{_id}'")
+                        f"update kpl_limit_up_record set _latest_limit_up_time='{d[3]}',_limit_up_time='{d[2]}',_hot_block_code_count={d[10]},_limit_up_high_info='{d[4]}' ,_update_time=now() where _id='{_id}'")
                     cls.latest_datas[_id] = d
             cls.latest_datas[_id] = d
 
@@ -53,6 +110,14 @@
                 for dd in old_datas:
                     if dd[2] not in code_block_dict[code]:
                         mysqldb.execute(f"delete from kpl_limit_up_record where _id='{dd[0]}'")
+                        logger_kpl_limit_up_reason_change.info(f"code-{dd[3]}:{dd[2]}-{code_block_dict[code]}")
+                        # 鏉垮潡鏇存敼杩�
+                        mysqldb.execute(
+                            f"update kpl_limit_up_record set _hot_block_change = f'{dd[2]}' where _day='{dd[1]}' and _code='{code}'")
+
+                        cls.__LimitUpCodesPlateKeyManager.set_today_limit_up_reason_change(code, dd[2],
+                                                                                           code_block_dict[code])
+
                         if dd[0] in cls.latest_datas:
                             cls.latest_datas.pop(dd[0])
         cls.total_datas = KPLLimitUpDataRecordManager.list_all(tool.get_now_date_str())
@@ -60,6 +125,7 @@
     @classmethod
     def load_total_datas(cls):
         cls.total_datas = KPLLimitUpDataRecordManager.list_all(tool.get_now_date_str())
+        cls.__LimitUpCodesPlateKeyManager.set_today_total_limit_up([(r[3], r[2]) for r in cls.total_datas])
 
     @staticmethod
     def list_all(day):
@@ -93,7 +159,7 @@
     @staticmethod
     def get_latest_blocks(code):
         wheres = []
-        for b in INVALID_BLOCKS:
+        for b in constant.KPL_INVALID_BLOCKS:
             wheres.append(f"hb.`_hot_block_name` != '{b}'")
         wheres = " and ".join(wheres)
         sql = f"SELECT GROUP_CONCAT(_hot_block_name) FROM (SELECT hb.`_hot_block_name`,hb.`_day` FROM `kpl_limit_up_record` hb WHERE hb.`_code`='{code}' AND {wheres} ORDER BY hb.`_day` DESC LIMIT 10) a  GROUP BY a._day ORDER BY a._day DESC LIMIT 1"
@@ -101,11 +167,22 @@
         return mysqldb.select_one(sql)
 
     # 鑾峰彇浠g爜鏈�杩戠殑鏉垮潡锛岃繑鍥瀃(鏉垮潡,鏃ユ湡)]
-    @staticmethod
-    def get_latest_infos(code, count):
-        sql = f"SELECT GROUP_CONCAT(_hot_block_name),`_day` FROM (SELECT hb.`_hot_block_name`,hb.`_day` FROM `kpl_limit_up_record` hb WHERE hb.`_code`='{code}' ORDER BY hb.`_day` DESC LIMIT 10) a  GROUP BY a._day ORDER BY a._day DESC LIMIT {count}"
+    @classmethod
+    def get_latest_infos(cls, code, count, contains_today=True):
+        # 鍙幏鍙栨渶杩�180澶╃殑鏁版嵁
+        min_day = tool.date_sub(tool.get_now_date_str(), 180)
+        sql = f"SELECT GROUP_CONCAT(_hot_block_name),`_day`,_blocks FROM (SELECT hb.`_hot_block_name`,hb.`_day`,hb._blocks FROM `kpl_limit_up_record` hb WHERE hb.`_code`='{code}' and hb.`_day` > '{min_day}' ORDER BY hb.`_day` DESC LIMIT 10) a  GROUP BY a._day ORDER BY a._day DESC LIMIT {count}"
         mysqldb = mysql_data.Mysqldb()
-        return mysqldb.select_all(sql)
+        results = mysqldb.select_all(sql)
+        if results and not contains_today and results[0][1] == tool.get_now_date_str():
+            return results[1:]
+        return results
+
+    @classmethod
+    def get_latest_blocks_set(cls, code):
+        results = cls.get_latest_infos(code, 10, False)
+        bs = set([b[0] for b in results])
+        return bs
 
 
 class KPLDataManager:
@@ -163,10 +240,14 @@
             line = lines[0]
             result = json.loads(line)
             list_ = kpl_util.parseDaBanData(result, kpl_util.DABAN_TYPE_LIMIT_UP)
-            KPLLimitUpDataRecordManager.save_record(day, list_)
+            # KPLLimitUpDataRecordManager.save_record(day, list_)
+            for r in list_:
+                print(r[-1], r[5])
+                KPLPlatManager().save_plat(r[-1], r[5])
 
-            print(day, list_)
+            # print(day, list_)
 
 
 if __name__ == "__main__":
-    print(KPLLimitUpDataRecordManager.get_latest_infos("000950", 4))
+    ds = set(["1", "2", "3"])
+    print(ds.pop())
diff --git a/third_data/kpl_util.py b/third_data/kpl_util.py
index 68fe651..eec6a68 100644
--- a/third_data/kpl_util.py
+++ b/third_data/kpl_util.py
@@ -30,7 +30,7 @@
 
 
 # 娑ㄥ仠浠g爜锛�
-# (浠g爜,鍚嶇О,棣栨娑ㄥ仠鏃堕棿,鏈�杩戞定鍋滄椂闂�,鍑犳澘,娑ㄥ仠鍘熷洜,鏉垮潡,瀹為檯娴侀��,涓诲姏鍑�棰�)
+# (浠g爜,鍚嶇О,棣栨娑ㄥ仠鏃堕棿,鏈�杩戞定鍋滄椂闂�,鍑犳澘,娑ㄥ仠鍘熷洜,鏉垮潡,瀹為檯娴侀��,涓诲姏鍑�棰�,娑ㄥ仠鍘熷洜浠g爜,娑ㄥ仠鍘熷洜浠g爜鏁伴噺)
 # (0,1,6,25,9,16,11,15,12)
 # 绔炰环浠g爜锛�
 # (浠g爜,鍚嶇О,娑ㄥ仠濮斾拱棰�,鏉垮潡,绔炰环鎴愪氦棰�,瀹為檯娴侀��)
@@ -62,13 +62,14 @@
     BEST_FENG_KOU = "best_feng_kou"
     FENG_XIANG = "feng_xiang"
     INDUSTRY_RANK = "industry_rank"
+    JINGXUAN_RANK = "jingxuan_rank"
 
 
 def __parseDaBanItemData(data, type):
     if type == DABAN_TYPE_BIDDING:
         return data[0], data[1], data[18], data[11], data[22], data[15]
     elif type == DABAN_TYPE_LIMIT_UP:
-        return data[0], data[1], data[6], data[25], data[9], data[16], data[11], data[15], data[12]
+        return data[0], data[1], data[6], data[25], data[9], data[16], data[11], data[15], data[12], data[26], data[27]
     elif type == DABAN_TYPE_OPEN_LIMIT_UP:
         return data[0], data[1], data[4], data[11], data[15]
     elif type == DABAN_TYPE_LIMIT_DOWN:
@@ -170,4 +171,65 @@
         pdata = __parseIndustry_rank(d)
         if pdata:
             fresult_.append(pdata)
-    return fresult_
\ No newline at end of file
+    return fresult_
+
+
+# 瑙f瀽鏉垮潡浠g爜
+def parsePlateCodes(data):
+    if type(data) == str:
+        data = json.loads(data)
+    if int(data["errcode"]) != 0:
+        raise Exception(f"瑙f瀽鏁版嵁鍑洪敊锛宔rrcode锛歿data['errcode']}")
+    list_ = data["list"]
+    fresult_ = []
+    for d in list_:
+        # (浠g爜,鍚嶇О,鐜颁环,娑ㄥ箙,鑷敱娴侀��,鍑犳澘锛岄緳鍑狅紝涓诲姏鍑�棰�,300w鍑�棰�,鏈烘瀯澧炰粨)
+        fresult_.append((d[0], d[1], d[5], d[6], d[10], d[23], d[24], d[13], d[50], d[42]))
+    return fresult_
+
+
+# 瑙f瀽姒傚康涓殑鏉垮潡寮哄害
+def parseSonPlat(data):
+    if type(data) == str:
+        data = json.loads(data)
+    if int(data["errcode"]) != 0:
+        raise Exception(f"瑙f瀽鏁版嵁鍑洪敊锛宔rrcode锛歿data['errcode']}")
+    list_ = data["List"]
+    fresult_ = []
+    for d in list_:
+        # (浠g爜,鍚嶇О,寮哄害)
+        fresult_.append((d[0], d[1], d[2]))
+    return fresult_
+
+
+def __money_desc(money):
+    if abs(money) > 100000000:
+        return f"{round(money / 100000000, 2)}浜�"
+    else:
+        return f"{round(money / 10000, 2)}涓�"
+
+
+def parseMarketIndustry(data):
+    if type(data) == str:
+        data = json.loads(data)
+    if int(data["errcode"]) != 0:
+        raise Exception(f"瑙f瀽鏁版嵁鍑洪敊锛宔rrcode锛歿data['errcode']}")
+    list_ = data["list"]
+    fresult_ = []
+    for d in list_:
+        # (浠g爜,鍚嶇О,娑ㄥ箙,涓诲姏鍑�棰�)
+        fresult_.append((d[0], d[1], d[3], d[6]))
+    return fresult_
+
+
+def parseMarketJingXuan(data):
+    if type(data) == str:
+        data = json.loads(data)
+    if int(data["errcode"]) != 0:
+        raise Exception(f"瑙f瀽鏁版嵁鍑洪敊锛宔rrcode锛歿data['errcode']}")
+    list_ = data["list"]
+    fresult_ = []
+    for d in list_:
+        # (浠g爜,鍚嶇О,寮哄害,涓诲姏鍑�棰�)
+        fresult_.append((d[0], d[1], d[2], d[6]))
+    return fresult_
diff --git a/ths_industry_util.py b/ths_industry_util.py
index 5ebd8e0..fa2ab73 100644
--- a/ths_industry_util.py
+++ b/ths_industry_util.py
@@ -17,7 +17,7 @@
     __code_map = {}
     __industry_map = {}
     mysqldb = mysql_data.Mysqldb()
-    results = mysqldb.select_all("select * from ths_industry_codes")
+    results = mysqldb.select_all("select _id,second_industry from ths_industry_codes")
     for r in results:
         code = r[0]
         industry = r[1]
diff --git a/tool.py b/tool.py
index 9fd60dd..c556175 100644
--- a/tool.py
+++ b/tool.py
@@ -39,6 +39,13 @@
     return date
 
 
+# 鏃ユ湡鍑忓幓澶氬皯澶�
+def date_sub(date_str, day, format="%Y-%m-%d"):
+    t_ = time.mktime(time.strptime(date_str, format))
+    t_ -= day * 24 * 60 * 60
+    return time.strftime(format, t.localtime(t_))
+
+
 def get_now_time_str():
     time_str = datetime.datetime.now().strftime("%H:%M:%S")
     return time_str
@@ -195,10 +202,11 @@
 
 
 if __name__ == "__main__":
-    print(trade_time_sub("13:18:00", "09:00:00")//60)
-    print(trade_time_sub("09:00:00","13:18:00") // 60)
+    print(trade_time_sub("13:18:00", "09:00:00") // 60)
+    print(trade_time_sub("09:00:00", "13:18:00") // 60)
     print(trade_time_sub("09:00:00", "09:30:00") // 60)
     print(trade_time_sub("09:30:00", "09:00:00") // 60)
+    print(date_sub("2023-05-12",180))
     # print(trade_time_sub("11:29:59", 5))
     # print(trade_time_sub("10:29:59", 10))
     # print(trade_time_add_second("13:29:59", 60))
diff --git a/trade/trade_manager.py b/trade/trade_manager.py
index d3d1714..0027416 100644
--- a/trade/trade_manager.py
+++ b/trade/trade_manager.py
@@ -78,7 +78,7 @@
 
     @classmethod
     def add_code(cls, code):
-        cls.__get_redis().sadd(cls.__key,code)
+        cls.__get_redis().sadd(cls.__key, code)
 
     @classmethod
     def remove_code(cls, code):
@@ -91,7 +91,6 @@
     @classmethod
     def clear(cls):
         cls.__get_redis().delete(cls.__key)
-
 
 
 # 鑾峰彇浜ゆ槗鐘舵��
@@ -117,6 +116,17 @@
     if keys is not None:
         for key in keys:
             if int(redis.get(key)) == state:
+                codes.append(key.replace("trade-state-", ''))
+    return codes
+
+
+def get_codes_by_trade_states(states):
+    redis = __redis_manager.getRedis()
+    keys = redis.keys("trade-state-*")
+    codes = []
+    if keys is not None:
+        for key in keys:
+            if int(redis.get(key)) in states:
                 codes.append(key.replace("trade-state-", ''))
     return codes
 
@@ -477,4 +487,4 @@
 
 
 if __name__ == "__main__":
-    set_trade_state("002351",TRADE_STATE_BUY_DELEGATED)
+    set_trade_state("002351", TRADE_STATE_BUY_DELEGATED)
diff --git a/ui/my_widget.py b/ui/my_widget.py
new file mode 100644
index 0000000..21c4b18
--- /dev/null
+++ b/ui/my_widget.py
@@ -0,0 +1,15 @@
+from tkinter import *
+
+
+class FlatButton(Button):
+    pixelVirtual = None
+
+    def __init__(self, master=None, **kw):
+        if self.pixelVirtual is None:
+            self.pixelVirtual = PhotoImage(width=1, height=1)
+        kw['relief'] = FLAT
+        kw["image"] = self.pixelVirtual,
+        kw["compound"] = "c"
+        if "height" not in kw:
+            kw["height"] = 20
+        super(FlatButton, self).__init__(master, kw)

--
Gitblit v1.8.0