Administrator
2023-05-15 045a5aa6434da6e83c3d850b17e7e58cd7b55ef5
开盘啦板块影响交易逻辑
16个文件已修改
4个文件已添加
1291 ■■■■ 已修改文件
constant.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gui.py 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/l2_data_manager_new.py 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
log.py 52 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
output/code_info_output.py 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
output/css/index.css 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
output/index.html 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
output/limit_up_data_filter.py 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
output/output_util.py 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server.py 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/block_info.py 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/code_plate_key_manager.py 240 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/data_server.py 280 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/kpl_api.py 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/kpl_data_manager.py 109 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/kpl_util.py 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ths_industry_util.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
tool.py 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/trade_manager.py 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ui/my_widget.py 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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 = ["一季报增长", "二季报增长", "三季报增长", "四季报增长", "业绩增长", "中报增长", "年报增长", "年报预增", "无", "次新股", "ST摘帽", "超跌",
                      "股权转让", "并购重组", "再融资", "年报预增", "次新股", " 专精特新", "壳资源"]
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="设置代码", command=lambda: setGPCode(ep_client.get(), ep.get(), code.get()), )
        btn = FlatButton(frame, text="设置代码", 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):
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"首板代码,没在想要买名单中且未打开涨停板,分数:{score}"
            if not is_limited_up:
                return False, True, f"首板代码,没在想要买名单中且未涨停过,分数:{score}"
            # if score_index >= 3:
            #     return False, True, f"分值:{score}未达到主动买入分数线"
            return True, False, ""
        else:
            return True, False, "在想买名单中"
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")
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"] = []
    ##############################主动买,被动买##################################
    # 返回主动买,被动买,不买的列表(代码, 名称, 得分, 是否涨停)
    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
    # 获取代码的历史涨停数据
    params["kpl_code_info"]["code_records"] = KPLLimitUpDataRecordManager.get_latest_infos(code, 4)
    # 获取代码的历史涨停数据,(涨停原因,日期,板块)
    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)
    # 获取这几天的涨停代码
    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])))
    # 获取今日代码的得分
    __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:
        # 获取涨停代码信息
        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():
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;
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>
output/limit_up_data_filter.py
New file
@@ -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()
# 忽略代码管理器
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
# 获取代码分数字典
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()
output/output_util.py
New file
@@ -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 ""
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("代码信息获取时间",code,round((time.time()-__start_time)*1000))
                    print("代码信息获取时间", code, round((time.time() - __start_time) * 1000))
                    pass
                # 获取最近2个交易日涨停代码
                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())
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()
    # 炸板:
    # (代码,名称,涨幅,板块,实际流通)
    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:
third_data/code_plate_key_manager.py
New file
@@ -0,0 +1,240 @@
"""
代码行业关键词管理
"""
# 涨停代码关键词板块管理
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
    # 获取能够买的行业关键字set
    @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()
    # 获取今日涨停数据,格式:[(代码,涨停原因)]
    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
# 目标代码关键词管理
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)))
    # 如果返回值不为None表示已经加载过历史原因了
    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}"
        # 看板块中是否已经有已经下单的或者成交的代码
        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})
        # 遍历已经成交/下单的代码,获取其涨停原因,然后和当前代码涨停原因做比较,有相同代码的不能买
        for c in codes:
            keys_, k1_, k11_, k2_, k3_, k4_ = cls.__TargetCodePlateKeyManager.get_plate_keys(c)
            # 实时涨停原因
            for k_ in k1_:
                # 当前代码已经有挂的或者成交的
                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])
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
        # 获取想买原因想买单的代码数量
        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]
            # (代码, 名称, 涨停状态(0 - 无状态 1-涨停 2-炸板), 龙几, 首板, 分值, 涨停时间, 原因, 相同原因代码数量, 自由流通, 涨停原因是否变化)
            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
        # 获取代码的历史涨停数据,(涨停原因,日期,板块)
        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
            # # (代码,名称,强度)
            # temp = kpl_util.parseSonPlat(datas)
            # temp.sort(key=lambda x: x[2])
            # temp.reverse()
            # fresult["plat_strength"] = temp
            # 获取涨停原因下面的列表
            datas = codes_by_plate_info
            # (代码,名称,现价,涨幅,自由流通,几板,龙几,主力净额,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")
            # 最终结果:(代码,名称,涨停状态(0-无状态 1-涨停 2-炸板),龙几,首板,分值,涨停时间,原因,相同原因代码数量,自由流通,涨停原因是否变化,涨幅,现价,黑名单,想买单,主力净值,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):
third_data/kpl_api.py
@@ -26,3 +26,42 @@
    if int(result["errcode"]) != 0:
        return None
    return result["ListJX"]
# 获取概念代码
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
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 = ["一季报增长", "二季报增长", "三季报增长", "四季报增长", "业绩增长", "中报增长", "年报增长", "年报预增", "无", "次新股", "ST摘帽", "超跌", "股权转让",
                  "并购重组"]
# 代码对应的涨停原因保存
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:
            # (代码, 名称, 首次涨停时间, 最近涨停时间, 几板, 涨停原因, 板块, 实际流通, 主力净额)
            plats[d[5]] = d[9]
        for p in plats:
            cls.__kplPlatManager.save_plat(plats[p], p)
        for d in records:
            # (代码, 名称, 首次涨停时间, 最近涨停时间, 几板, 涨停原因, 板块, 实际流通, 主力净额,涨停原因代码,涨停原因代码数量)
            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)
    # 获取代码最近的板块,返回[(板块,日期)]
    @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())
third_data/kpl_util.py
@@ -30,7 +30,7 @@
# 涨停代码:
# (代码,名称,首次涨停时间,最近涨停时间,几板,涨停原因,板块,实际流通,主力净额)
# (代码,名称,首次涨停时间,最近涨停时间,几板,涨停原因,板块,实际流通,主力净额,涨停原因代码,涨停原因代码数量)
# (0,1,6,25,9,16,11,15,12)
# 竞价代码:
# (代码,名称,涨停委买额,板块,竞价成交额,实际流通)
@@ -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_
    return fresult_
# 解析板块代码
def parsePlateCodes(data):
    if type(data) == str:
        data = json.loads(data)
    if int(data["errcode"]) != 0:
        raise Exception(f"解析数据出错,errcode:{data['errcode']}")
    list_ = data["list"]
    fresult_ = []
    for d in list_:
        # (代码,名称,现价,涨幅,自由流通,几板,龙几,主力净额,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_
# 解析概念中的板块强度
def parseSonPlat(data):
    if type(data) == str:
        data = json.loads(data)
    if int(data["errcode"]) != 0:
        raise Exception(f"解析数据出错,errcode:{data['errcode']}")
    list_ = data["List"]
    fresult_ = []
    for d in list_:
        # (代码,名称,强度)
        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"解析数据出错,errcode:{data['errcode']}")
    list_ = data["list"]
    fresult_ = []
    for d in list_:
        # (代码,名称,涨幅,主力净额)
        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"解析数据出错,errcode:{data['errcode']}")
    list_ = data["list"]
    fresult_ = []
    for d in list_:
        # (代码,名称,强度,主力净额)
        fresult_.append((d[0], d[1], d[2], d[6]))
    return fresult_
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]
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))
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)
ui/my_widget.py
New file
@@ -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)