Administrator
2023-04-21 0ed2c53acd278d57a39390fd4db78c5aaf088e0a
开盘啦数据解析
27个文件已修改
4个文件已添加
1887 ■■■■ 已修改文件
code_data_util.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
code_nature_analyse.py 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
constant.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
data_export_util.py 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gpcode_manager.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
gui.py 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
juejin.py 224 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/cancel_buy_strategy.py 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/code_price_manager.py 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/l2_data_manager_new.py 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/l2_data_util.py 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/l2_log.py 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2_data_util.py 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2_trade_test.py 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
log.py 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ocr/ocr_util.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
output/code_info_output.py 282 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
output/css/style.css 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server.py 95 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/hot_block.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/hot_block_data_process.py 184 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/kpl_util.py 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/res/kpl.txt 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/xgb.py 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tool.py 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/current_price_process_manager.py 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/deal_big_money_manager.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/first_code_score_manager.py 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/l2_trade_factor.py 119 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/trade_gui.py 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/trade_manager.py 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
code_data_util.py
@@ -31,7 +31,7 @@
    @classmethod
    def save(cls, code, val, unit):
        redis = _redisManager.getRedis()
        redis.setex("zyltgb-{}".format(code), 60 * 60 * 24 * 10,
        redis.setex("zyltgb-{}".format(code), tool.get_expire(),
                    round(float(val) * 100000000) if int(unit) == 0 else round(
                        float(val) * 10000))
@@ -66,4 +66,7 @@
if __name__ == "__main__":
    print(is_same_code_with_price("000617", 17.89))
    redis = _redisManager.getRedis()
    keys = redis.keys("zyltgb-*")
    for key in keys:
        redis.delete(key)
code_nature_analyse.py
@@ -85,37 +85,40 @@
# 获取股性
# 返回(是否涨停,首板溢价率是否大于0.6)
# 返回(是否涨停,首板溢价率,首板炸板溢价率)
def get_nature(record_datas):
    limit_up = is_have_limit_up(record_datas)
    limit_up_count = get_first_limit_up_count(record_datas)
    premium_rate = get_limit_up_premium_rate(record_datas)
    result = (limit_up, premium_rate >= 0.6, premium_rate)
    open_premium_rate = get_open_limit_up_premium_rate(record_datas)
    result = (limit_up_count, premium_rate, open_premium_rate)
    return result
# 获取涨幅
def get_lowest_price_rate(record_datas):
    datas = copy.deepcopy(record_datas)
    datas.sort(key=lambda x: x["bob"])
    datas = datas[-15:]
    low_price = datas[0]["close"]
    date = None
    datas = datas[-10:]
    for data in datas:
        if low_price > data["close"]:
            low_price = data["close"]
        limit_up_price = float(gpcode_manager.get_limit_up_price_by_preprice(data["pre_close"]))
        if abs(limit_up_price - data["high"]) < 0.01:
            date = data['bob'].strftime("%Y-%m-%d")
    return (datas[-1]["close"] - low_price) / low_price, date
            return round((datas[-1]["close"] - data["close"]) / data["close"], 4), date
    return 0, ''
# 是否有涨停
def is_have_limit_up(datas):
def get_first_limit_up_count(datas):
    datas = copy.deepcopy(datas)
    count = 0
    for i in range(len(datas)):
        item = datas[i]
        limit_up_price = float(gpcode_manager.get_limit_up_price_by_preprice(item["pre_close"]))
        if abs(limit_up_price - item["close"]) < 0.01:
            return True, item['bob'].strftime("%Y-%m-%d")
    return False, ''
        # 获取首板涨停次数
        if __is_limit_up(item) and i>0 and not __is_limit_up(datas[i-1]):
            # 首板涨停
            count+=1
    return count
# 是否破前高
@@ -255,6 +258,12 @@
    return max_volume, average_volume
# 是否涨停
def __is_limit_up(data):
    limit_up_price = float(gpcode_manager.get_limit_up_price_by_preprice(data["pre_close"]))
    return abs(limit_up_price - data["close"]) < 0.001
# 首板涨停溢价率
def get_limit_up_premium_rate(datas):
    datas = copy.deepcopy(datas)
@@ -263,13 +272,38 @@
    for i in range(0, len(datas)):
        item = datas[i]
        limit_up_price = float(gpcode_manager.get_limit_up_price_by_preprice(item["pre_close"]))
        if abs(limit_up_price - item["close"]) < 0.001 and abs(
                limit_up_price - datas[i - 1]["close"]) >= 0.001 and 0 < i < len(datas) - 1:
            # 首板涨停
            rate = (datas[i + 1]["high"] - datas[i + 1]["pre_close"]) / datas[i + 1]["pre_close"]
            first_rate_list.append(rate)
        if abs(limit_up_price - item["close"]) < 0.001:
            if 0 < i < len(datas) - 1 and not __is_limit_up(datas[i - 1]):
                # 首板涨停
                rate = (datas[i + 1]["high"] - datas[i + 1]["pre_close"]) / datas[i + 1]["pre_close"]
                first_rate_list.append(rate)
    if not first_rate_list:
        return 0
        return None
    count = 0
    for rate in first_rate_list:
        if rate >= 0.01:
            count += 1
    return count / len(first_rate_list)
# 首板炸板溢价率
def get_open_limit_up_premium_rate(datas):
    datas = copy.deepcopy(datas)
    datas.sort(key=lambda x: x["bob"])
    first_rate_list = []
    for i in range(0, len(datas)):
        item = datas[i]
        limit_up_price = float(gpcode_manager.get_limit_up_price_by_preprice(item["pre_close"]))
        if abs(limit_up_price - item["high"]) < 0.001 and abs(limit_up_price - item["close"]) > 0.001:
            #
            limit_up_price = float(gpcode_manager.get_limit_up_price_by_preprice(datas[i - 1]["pre_close"]))
            if 0 < i < len(datas) - 1 and not __is_limit_up(datas[i - 1]):
                # 前一天未涨停
                rate = (datas[i + 1]["high"] - item["high"]) / item["high"]
                first_rate_list.append(rate)
    if not first_rate_list:
        return None
    count = 0
    for rate in first_rate_list:
        if rate >= 0.01:
constant.py
@@ -26,3 +26,10 @@
L2_MIN_MONEY = 500000
# 每个L2设备的代码数量
L2_CODE_COUNT_PER_DEVICE = 6
# 买入分数分档
BUY_SCORE_RANK_0 = 170
BUY_SCORE_RANK_1 = 220
BUY_SCORE_RANK_2 = 240
BUY_SCORE_RANK_3 = 260
data_export_util.py
@@ -12,6 +12,7 @@
import l2.l2_data_util
import log
from l2 import l2_data_source_util
from trade import deal_big_money_manager
def export_l2_excel(code, date=None):
@@ -195,7 +196,15 @@
    return file_name
def test(code):
    progresses = log.export_trade_progress(code)
    local_today_datas = log.load_l2_from_log("2023-04-04")
    datas = local_today_datas[code]
    num_operate_map = {}
    l2.l2_data_util.load_num_operate_map(num_operate_map, code, datas)
    for progress in progresses:
        deal_big_money_manager.set_trade_progress(code, progress, datas, num_operate_map[code])
if __name__ == "__main__":
    codes = ["600573"]
    for code in codes:
        export_l2_excel(code)
    export_l2_excel("600072")
gpcode_manager.py
@@ -636,4 +636,4 @@
if __name__ == '__main__':
    print(get_can_listen_pos())
    set_price_pre("601858", 27.67)
gui.py
@@ -3,6 +3,8 @@
"""
from tkinter import *
from tkinter.messagebox import *
import numpy
import tkintertable
import win32gui
@@ -142,9 +144,6 @@
            for i in range(0, len(content)):
                text.tag_add('error', "{}.{}".format(line, i))
        def sync_target_codes():
            server.sync_target_codes_to_ths()
        def click():
            text.delete('1.0', END)
@@ -206,9 +205,6 @@
        btn = Button(frame, text="运行环境检测", command=click)
        btn.place(x=5, y=5)
        btn = Button(frame, text="同步THS目标标的", command=sync_target_codes)
        btn.place(x=100, y=5)
        frame.grid(row=1, column=2)
@@ -327,7 +323,12 @@
        def re_distribute_buy_win():
            try:
                juejin.distribute_buy_win()
                if tool.trade_time_sub(tool.get_now_time_str(), "09:30:00") > 0:
                    raise Exception("只能9:30之前重新分配窗口")
                datas = JueJinManager.get_codes_limit_rate(gpcode_manager.get_gp_list())
                matrix = numpy.array(datas)
                codes = matrix[:, 0].tolist()
                trade_gui.re_distribute_buy_win(codes)
                refresh_trade_buy_win_data()
                showinfo("提示", "分配完成")
            except Exception as e:
@@ -347,7 +348,8 @@
                normal = False
            try:
                trade_gui.THSGuiTrade.checkEnv()
                cl_win.configure(text="正常", foreground="#008000")
                cancel_win_num = trade_gui.THSGuiTrade.getCancelBuyWins()
                cl_win.configure(text=f"正常({len(cancel_win_num)})", foreground="#008000")
            except Exception as e:
                normal = False
                cl_win.configure(text="异常:{}".format(str(e)), foreground="#FF7F27")
@@ -610,7 +612,21 @@
        width = 800
        height = 360
        frame = Frame(root, {"height": height, "width": width, "bg": "#DDDDDD"})
        cl = Label(frame, text="L2采集状态", bg="#DDDDDD")
        trade_info= ""
        for_color = "#008000"
        if constant.TEST:
            trade_info += "测试环境"
            for_color = "#FF7F27"
        else:
            trade_info += "正式环境"
        trade_info += " "
        if constant.TRADE_ENABLE:
            trade_info += "初始允许交易"
        else:
            trade_info += "初始禁止交易"
            for_color = "#FF7F27"
        cl = Label(frame, text=f"{trade_info}", bg="#DDDDDD",foreground=f"{for_color}")
        cl.place(x=5, y=5)
        accept_l2 = IntVar()
juejin.py
@@ -31,9 +31,8 @@
import authority
import decimal
from trade import trade_gui, l2_trade_util
from trade import trade_gui, l2_trade_util, trade_manager
from l2.cancel_buy_strategy import L2LimitUpSellStatisticUtil
from l2_code_operate import L2CodeOperate
from log import logger_juejin_tick, logger_system
from trade.trade_data_manager import CodeActualPriceProcessor
from trade.trade_queue_manager import JueJinBuy1VolumnManager
@@ -74,7 +73,7 @@
    global_data_loader.load_volumn()
    # 9点25之前删除所有代码
    if tool.trade_time_sub(tool.get_now_time_str(), "09:25:00") <= 0:
    if tool.trade_time_sub(tool.get_now_time_str(), "09:25:00") <= 0 or True:
        # 删除L2监听代码
        gpcode_manager.clear_listen_codes()
        # 删除首板代码
@@ -87,6 +86,8 @@
        l2_trade_util.WhiteListCodeManager.clear()
        # 清空想要买
        gpcode_manager.WantBuyCodesManager.clear()
        # 清空分数禁止代码
        trade_manager.ForbiddenBuyCodeByScoreManager.clear()
# 每日初始化
@@ -101,7 +102,7 @@
    # 今日实时涨停
    global_data_loader.add_limit_up_codes([], True)
    # 主要获取收盘价
    get_latest_info(None)
    __get_latest_info(None)
    # 获取60天最大量与昨日量
    global_util.today_volumn.clear()
    global_util.max60_volumn.clear()
@@ -147,11 +148,11 @@
    t1.start()
    # 多个时间点获取收盘价
    gmapi.schedule(schedule_func=get_latest_info, date_rule='1d', time_rule='08:30:00')
    gmapi.schedule(schedule_func=get_latest_info, date_rule='1d', time_rule='08:50:00')
    gmapi.schedule(schedule_func=get_latest_info, date_rule='1d', time_rule='09:28:00')
    gmapi.schedule(schedule_func=get_current_info, date_rule='1d', time_rule='09:25:00')
    gmapi.schedule(schedule_func=get_current_info, date_rule='1d', time_rule='09:29:00')
    gmapi.schedule(schedule_func=__get_latest_info, date_rule='1d', time_rule='08:30:00')
    gmapi.schedule(schedule_func=__get_latest_info, date_rule='1d', time_rule='08:50:00')
    gmapi.schedule(schedule_func=__get_latest_info, date_rule='1d', time_rule='09:28:00')
    gmapi.schedule(schedule_func=__get_current_info, date_rule='1d', time_rule='09:25:00')
    gmapi.schedule(schedule_func=__get_current_info, date_rule='1d', time_rule='09:29:00')
    re_subscribe_tick()
    # re_subscribe_bar()
@@ -162,7 +163,7 @@
            gpcode_manager.init_listen_code_by_pos(client, i)
def get_latest_info(context):
def __get_latest_info(context):
    # 初始化内容
    clients = authority.get_l2_clients()
    for c in clients:
@@ -183,7 +184,7 @@
# 获取最新的信息
def get_current_info():
def __get_current_info():
    data = gpcode_manager.get_gp_list()
    results = JueJinManager.get_gp_current_info(data)
    logger_juejin_tick.debug("定时获取:{}", results)
@@ -192,7 +193,6 @@
        symbol = result['symbol']
        # 保存最新价
        symbol = symbol.split(".")[1]
        accpt_price(symbol, price)
# 设置收盘价
@@ -244,150 +244,7 @@
        #     L2LimitUpMoneyStatisticUtil.verify_num(data_[0], data_[2], data_[1])
        # print(tick["created_at"],tick["quotes"][0]["bid_v"])
        accpt_price(symbol, price)
        __prices_now[symbol] = price
# 获取到现价
def accpt_price(code, price, price_from="juejin"):
    return
    gpcode_manager.set_price(code, price)
    # 获取收盘价
    pricePre = gpcode_manager.get_price_pre(code)
    if pricePre is not None:
        rate = round((price - pricePre) * 100 / pricePre, 1)
        if rate >= 7:
            logger_juejin_tick.info("{}-{}-{}", code, price, rate)
            if not gpcode_manager.is_listen_old(code) and not gpcode_manager.is_operate(
                    code) and not gpcode_manager.is_listen_full():
                L2CodeOperate.get_instance().add_operate(1, code, "现价变化,rate-{} from-{}".format(rate, price_from))
            # 进入监控
        elif rate < 5:
            # 移除监控
            if gpcode_manager.is_listen_old(code) and not gpcode_manager.is_operate(code):
                L2CodeOperate.get_instance().add_operate(0, code, "现价变化,rate-{} from-{}".format(rate, price_from))
# 获取到现价
def accept_prices(prices):
    # 获取首板代码
    first_codes = gpcode_manager.get_first_gp_codes()
    print("价格代码数量:", len(prices))
    __actualPriceProcessor.save_current_price_codes_count(len(prices))
    # 采集的代码数量不对
    if len(gpcode_manager.get_gp_list()) - len(prices) > 10:
        return
    now_str = tool.get_now_time_str()
    now_strs = now_str.split(":")
    now_second = int(now_strs[0]) * 60 * 60 + int(now_strs[1]) * 60 + int(now_strs[2])
    start = 60 * 60 * 9 + 31 * 60
    if False:
        for d in prices:
            code, price = d["code"], float(d["price"])
            accpt_price(code, price, "ths")
    else:
        _code_list = []
        _delete_list = []
        for d in prices:
            code, price = d["code"], float(d["price"])
            gpcode_manager.set_price(code, price)
            # 获取收盘价
            pricePre = gpcode_manager.get_price_pre(code)
            if pricePre is not None:
                rate = round((price - pricePre) * 100 / pricePre, 2)
                if first_codes and code in first_codes:
                    rate = rate / 2
                if rate >= 0:
                    # 暂存涨幅为正的代码
                    _code_list.append((rate, code))
                else:
                    # 暂存涨幅为负的代码
                    _delete_list.append((rate, code))
                try:
                    __actualPriceProcessor.process_rate(code, rate, now_str)
                except Exception as e:
                    logging.exception(e)
                try:
                    __actualPriceProcessor.save_current_price(code, price,
                                                              gpcode_manager.get_limit_up_price_by_preprice(
                                                                  pricePre) == tool.to_price(
                                                                  decimal.Decimal(d["price"])))
                except Exception as e:
                    logging.exception(e)
        # -------------------------------处理交易位置分配---------------------------------
        # 排序
        new_code_list = sorted(_code_list, key=lambda e: (e.__getitem__(0), e.__getitem__(1)), reverse=True)
        # 预填充下单代码
        _buy_win_codes = []
        for d in new_code_list:
            _buy_win_codes.append(d[1])
        for d in _delete_list:
            _buy_win_codes.append(d[1])
        try:
            trade_gui.THSBuyWinManagerNew.fill_codes(_buy_win_codes)
        except Exception as e:
            logging.exception(e)
            pass
        # -------------------------------处理L2监听---------------------------------
        client_ids = client_manager.getValidL2Clients()
        # 最多填充的代码数量
        max_count = len(client_ids) * constant.L2_CODE_COUNT_PER_DEVICE
        if max_count == 0:
            max_count = constant.L2_CODE_COUNT_PER_DEVICE
        _delete_list = []
        for item in new_code_list:
            if l2_trade_util.is_in_forbidden_trade_codes(item[1]) or item[0] < 0:
                _delete_list.append(item)
        for item in _delete_list:
            new_code_list.remove(item)
        # 截取前几个代码填充
        add_list = new_code_list[:max_count]
        # 后面的代码全部删除
        _delete_list.extend(new_code_list[max_count:])
        add_code_list = []
        del_code_list = []
        for d in add_list:
            add_code_list.append(d[1])
        for d in _delete_list:
            del_code_list.append(d[1])
        # 后面的代码数量
        # 先删除应该删除的代码
        for code in del_code_list:
            if gpcode_manager.is_listen_old(code):
                # 判断是否在监听里面
                L2CodeOperate.get_instance().add_operate(0, code, "现价变化")
        # 增加应该增加的代码
        for code in add_code_list:
            if not gpcode_manager.is_listen_old(code):
                L2CodeOperate.get_instance().add_operate(1, code, "现价变化")
        # 获取卡位数量
        free_count = gpcode_manager.get_free_listen_pos_count()
        if free_count < 2:
            # 空闲位置不足
            listen_codes = gpcode_manager.get_listen_codes()
            for code in listen_codes:
                if not gpcode_manager.is_in_gp_pool(code):
                    client_id, pos = gpcode_manager.get_listen_code_pos(code)
                    gpcode_manager.set_listen_code_by_pos(client_id, pos, "")
                    free_count += 1
                    if free_count > 2:
                        break
        print(add_code_list, del_code_list)
def on_bar(context, bars):
    print("on_bar", bars)
@@ -421,8 +278,8 @@
        elif action == 'accpt_price':
            try:
                datas = jsonValue["data"]
                for data in datas:
                    accpt_price(data["code"], float(data["price"]))
                # for data in datas:
                #     accpt_price(data["code"], float(data["price"]))
            except Exception as e:
                print(str(e))
@@ -557,15 +414,6 @@
        return gmapi.get_trading_dates("SHSE", start_date, end_date)
def trade(code, volume):
    account_id, s_id, token = getAccountInfo()
    gmapi.set_token(token)
    gmapi.set_account_id(account_id)
    result = gmapi.order_volume(symbol=code, volume=volume, side=gmapi.OrderSide_Sell,
                                order_type=gmapi.OrderType_Market, position_effect=gmapi.PositionEffect_Close)
    print(result)
# 获取近90天的最大量与最近的量
def get_volumns(codes):
    end = datetime.datetime.now()
@@ -639,47 +487,5 @@
    return max_volume, max_volume, max_volume_date.strftime("%Y-%m-%d")
# 是否有涨停
def is_have_limit_up(datas):
    for i in range(len(datas)):
        item = datas[i]
        limit_up_price = float(gpcode_manager.get_limit_up_price_by_preprice(item["pre_close"]))
        if abs(limit_up_price - item["close"]) < 0.01:
            return True
    return False
# 首板涨停溢价率
def get_limit_up_money_percent(datas):
    datas.sort(key=lambda x: x["bob"])
    first_rate_list = []
    for i in range(0, len(datas)):
        item = datas[i]
        limit_up_price = float(gpcode_manager.get_limit_up_price_by_preprice(item["pre_close"]))
        if abs(limit_up_price - item["close"]) < 0.001 and abs(
                limit_up_price - datas[i - 1]["close"]) >= 0.001 and 0 < i < len(datas) - 1:
            # 首板涨停
            rate = (datas[i + 1]["high"] - datas[i + 1]["pre_close"]) / datas[i + 1]["pre_close"]
            first_rate_list.append(rate)
    if not first_rate_list:
        return 1
    count = 0
    for rate in first_rate_list:
        if rate >= 0.01:
            count += 1
    return count / len(first_rate_list)
# 根据涨幅高低分配交易窗口
def distribute_buy_win():
    if tool.trade_time_sub(tool.get_now_time_str(), "09:30:00") > 0:
        raise Exception("只能9:30之前重新分配窗口")
    datas = JueJinManager.get_codes_limit_rate(gpcode_manager.get_gp_list())
    matrix = numpy.array(datas)
    codes = matrix[:, 0].tolist()
    trade_gui.THSBuyWinManagerNew.fill_codes(codes)
if __name__ == '__main__':
    print(JueJinManager.get_trading_dates("2023-03-01", "2023-03-29"))
    init_data()
l2/cancel_buy_strategy.py
@@ -63,15 +63,20 @@
    # 计算净大单
    @classmethod
    def __compute_left_big_num(cls, code, buy_single_index, start_index, end_index, total_data, volume_rate_index):
        # 获取大单的最小手数
        left_big_num = 0
        # 点火大单数量
        fire_count = cls.__sCancelParamsManager.get_max_exclude_count(volume_rate_index)
        return cls.compute_left_big_num(code, buy_single_index, start_index, end_index, total_data, fire_count, constant.S_CANCEL_MIN_MONEY)
    # 计算未撤的总手数
    @classmethod
    def compute_left_big_num(cls, code, buy_single_index, start_index, end_index, total_data, fire_count, min_money_w):
        # 获取大单的最小手数
        left_big_num = 0
        for i in range(start_index, end_index + 1):
            data = total_data[i]
            val = data["val"]
            # 去除非大单
            if val["num"] * float(val["price"]) <= constant.S_CANCEL_MIN_MONEY * 100:
            if val["num"] * float(val["price"]) <= min_money_w * 100:
                continue
            if L2DataUtil.is_limit_up_price_buy(val):
@@ -108,8 +113,6 @@
                    buy_volume_rate_index,
                    volume_rate_index,
                    need_cancel=True):
        if start_index >= 217:
            print("进入调试")
        # 只守护30s
        buy_exec_time = total_data[buy_exec_index]["val"]["time"]
        if tool.trade_time_sub(total_data[start_index]["val"]["time"],
@@ -194,14 +197,21 @@
                            if int(total_data[buy_single_index]["val"]["time"].replace(":", "")) <= int(
                                    buy_time.replace(":", "")):
                                # 买入时间在囊括范围内
                                if tool.trade_time_sub(tool.trade_time_add_second(buy_exec_time, range_seconds),buy_time) >= 0:
                                if tool.trade_time_sub(tool.trade_time_add_second(buy_exec_time, range_seconds),
                                                       buy_time) >= 0:
                                    cancel_num += data["re"] * int(val["num"])
                    # 保存数据
                    if need_cancel:
                        if cancel_num / max(buy_num, 1) > cancel_rate_threshold:
                        rate__ = round(cancel_num / max(buy_num, 1), 2)
                        if rate__ > cancel_rate_threshold:
                            l2_log.trade_record(code, "S撤范围", "'start_index':{} , 'end_index':{} ,'range_seconds':{}",
                                                buy_single_index,
                                                i,
                                                range_seconds)
                            l2_log.trade_record(code, "S撤", "'index':{} , 'rate':{} , 'target_rate':{}", i, rate__,
                                                cancel_rate_threshold)
                            return True, total_data[i]
        finally:
@@ -364,7 +374,15 @@
                                                                                                     local_today_num_operate_map)
                    if buy_index is not None and buy_index in watch_indexs_dict:
                        cancel_num += data["re"] * val["num"]
                        if cancel_num / total_nums > cancel_rate_threshold:
                        rate__ = round(cancel_num / total_nums, 2)
                        if rate__ > cancel_rate_threshold:
                            indexs__ = list(watch_indexs_dict.keys())
                            indexs__.sort()
                            l2_log.trade_record(code, "H撤范围", "'start_index':{},'end_index':{}, 'count':{}",
                                                indexs__[0], indexs__[-1],
                                                len(watch_indexs_dict.keys()))
                            l2_log.trade_record(code, "H撤", "'index':{} , 'rate':{} ,'target_rate':{}", i, rate__,
                                                cancel_rate_threshold)
                            return True, data
        finally:
            l2_log.cancel_debug(code, "H级撤单计算结果 范围:{}-{} 处理进度:{} 取消计算结果:{}/{} 目标撤单比例:{}", start_index, end_index,
@@ -534,7 +552,7 @@
        final_watch_list = list(watch_set)
        final_watch_list.sort(key=lambda x: x[0])
        logger_l2_h_cancel.info(f"code-{code}  H撤监控执行位相邻单:{final_watch_list}")
        logger_l2_h_cancel.info(f"code-{code}  H撤监控执行位相邻单:{final_watch_list} 目标计算数量:{MIN_H_COUNT}")
        # 保存计算范围
        cls.__save_watch_index_set_after_exec(code, final_watch_list, process_index, total_count, big_num_count,
                                              finished)
l2/code_price_manager.py
@@ -5,10 +5,12 @@
import tool
from db import redis_manager
from log import logger_trade_queue_price_info
class Buy1PriceManager:
    __redisManager = redis_manager.RedisManager(1)
    __latest_data = {}
    @classmethod
    def __get_redis(cls):
@@ -30,15 +32,24 @@
    # 处理
    @classmethod
    def process(cls, code, buy_1_price, time_str, limit_up_price):
    def process(cls, code, buy_1_price, time_str, limit_up_price, sell_1_price, sell_1_volumn):
        data_str = f"{buy_1_price},{time_str},{limit_up_price},{sell_1_price},{sell_1_volumn}"
        if cls.__latest_data.get(code) == data_str:
            return
        cls.__latest_data[code] = data_str
        # 记录日志
        logger_trade_queue_price_info.info(
            f"code={code} data: time_str-{time_str}, buy_1_price-{buy_1_price},limit_up_price-{limit_up_price},sell_1_price-{sell_1_price},sell_1_volumn-{sell_1_volumn}")
        # 买1价格不能小于1块
        if float(buy_1_price) < 1.0:
            return
        is_limit_up = abs(float(limit_up_price) - float(buy_1_price)) < 0.01
        old_limit_up_time, old_open_limit_up_time = cls.__get_buy1_price_info(code)
        if old_limit_up_time and old_open_limit_up_time:
            return
        if is_limit_up and old_limit_up_time is None:
        if is_limit_up and old_limit_up_time is None and float(sell_1_price) < 0.1 and int(sell_1_volumn) <= 0:
            # 卖1消失,买1为涨停价则表示涨停
            cls.__save_buy1_price_info(code, time_str, None)
        elif old_limit_up_time and not is_limit_up and old_open_limit_up_time is None:
            # 有涨停时间,当前没有涨停,之前没有打开涨停
@@ -55,21 +66,17 @@
    # 获取涨停信息
    # 返回涨停时间与炸板时间
    @classmethod
    def get_limit_up_info(cls,code):
    def get_limit_up_info(cls, code):
        old_limit_up_time, old_open_limit_up_time = cls.__get_buy1_price_info(code)
        return old_limit_up_time, old_open_limit_up_time
    # 设置涨停时间
    @classmethod
    def set_limit_up_time(cls, code, time_str):
        limit_up_time, open_limit_up_time = cls.get_limit_up_info(code)
        if limit_up_time is None:
            cls.__save_buy1_price_info(code, time_str, None)
if __name__ == "__main__":
    code = "000333"
    limit_up_price = "54.00"
    Buy1PriceManager.process("000333", "53.00", "09:56:00", limit_up_price)
    print(Buy1PriceManager.is_can_buy(code))
    Buy1PriceManager.process("000333", "54.00", "09:57:00", limit_up_price)
    print(Buy1PriceManager.is_can_buy(code))
    Buy1PriceManager.process("000333", "53.00", "09:58:00", limit_up_price)
    print(Buy1PriceManager.is_can_buy(code))
    Buy1PriceManager.process("000333", "54.00", "09:59:00", limit_up_price)
    print(Buy1PriceManager.is_can_buy(code))
    print(Buy1PriceManager.get_limit_up_info("002777"))
l2/l2_data_manager_new.py
@@ -6,6 +6,7 @@
import code_data_util
import code_volumn_manager
import constant
import global_data_loader
import global_util
import gpcode_manager
import industry_codes_sort
@@ -15,6 +16,7 @@
from db import redis_manager
import ths_industry_util
import tool
from third_data import hot_block, hot_block_data_process
from trade import trade_data_manager, 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
@@ -24,7 +26,7 @@
from l2.l2_data_util import local_today_datas, L2DataUtil, load_l2_data, local_today_num_operate_map, local_latest_datas
import l2.l2_data_util
from log import logger_l2_trade, logger_l2_trade_cancel, logger_l2_trade_buy, logger_l2_process, logger_l2_error, \
    logger_buy_score
    logger_place_order_score
# TODO l2数据管理
from trade.trade_data_manager import CodeActualPriceProcessor
@@ -173,7 +175,6 @@
            score_dict[code] = score
        return score_dict
    @classmethod
    # 数据处理入口
    # datas: 本次截图数据
@@ -251,7 +252,9 @@
            cls.__l2PlaceOrderParamsManagerDict[code] = l2_trade_factor.L2PlaceOrderParamsManager(code, is_first_code,
                                                                                                  volume_rate,
                                                                                                  volume_rate_index,
                                                                                                  score)
                                                                                                  score,
                                                                                                  total_datas[-1][
                                                                                                      'val']['time'])
            cls.volume_rate_info[code] = (volume_rate, volume_rate_index)
            latest_time = add_datas[len(add_datas) - 1]["val"]["time"]
@@ -434,6 +437,7 @@
        if cancel_data:
            l2_log.debug(code, "触发撤单,撤单位置:{} ,撤单原因:{}", cancel_data["index"], cancel_msg)
            l2_log.trade_record(code, "撤单", "'index':{} , 'msg':'{}'", cancel_data["index"], cancel_msg)
            # 撤单
            if cls.cancel_buy(code, cancel_msg):
                _start_time = l2_data_log.l2_time(code, tool.get_now_timestamp() - _start_time,
@@ -470,17 +474,17 @@
        if code in cls.unreal_buy_dict:
            cls.unreal_buy_dict.pop(code)
        buy_single_index, buy_exec_index, buy_compute_index, num, count, max_num_set, buy_volume_rate = cls.__get_order_begin_pos(
            code)
        if not can:
            l2_log.debug(code, "不可以下单,原因:{}", reason)
            if need_clear_data:
                buy_single_index, buy_exec_index, buy_compute_index, num, count, max_num_set, buy_volume_rate = cls.__get_order_begin_pos(
                    code)
                trade_result_manager.real_cancel_success(code, buy_single_index, buy_exec_index,
                                                         local_today_datas.get(code))
            return
        else:
            l2_log.debug(code, "可以下单,原因:{}", reason)
            logger_buy_score.info(f"{code}:{cls.__l2PlaceOrderParamsManagerDict[code].score_info}")
            try:
                l2_log.debug(code, "开始执行买入")
                trade_manager.start_buy(code, capture_timestamp, last_data,
@@ -488,6 +492,12 @@
                ################下单成功处理################
                trade_result_manager.real_buy_success(code)
                l2_log.debug(code, "执行买入成功")
                params_desc = cls.__l2PlaceOrderParamsManagerDict[code].get_buy_rank_desc()
                l2_log.debug(code, params_desc)
                l2_log.trade_record(code, "下单",
                                    "'buy_start_index':{} ,'buy_exec_index':{},'volume_reate':{},'score':{},'desc':'{}'",
                                    buy_single_index, buy_exec_index, cls.volume_rate_info[code][0],
                                    cls.__l2PlaceOrderParamsManagerDict[code].score, params_desc)
            except Exception as e:
                l2_log.debug(code, "执行买入异常:{}", str(e))
                pass
@@ -662,13 +672,71 @@
    def __can_buy_first(cls, code):
        if not trade_manager.TradeStateManager.is_can_buy():
            return False, True, f"今日已禁止交易"
        limit_up_info = code_price_manager.Buy1PriceManager.get_limit_up_info(code)
        if limit_up_info[0] is None and False:
            total_data = local_today_datas.get(code)
            buy_single_index, buy_exec_index, buy_compute_index, num, count, max_num_set, buy_volume_rate = cls.__get_order_begin_pos(
                code)
            # 之前没有涨停过
            # 统计买入信号位到当前位置没有撤的大单金额
            min_money_w = l2_data_util.get_big_money_val(float(total_data[buy_single_index]["val"]["price"])) // 10000
            left_big_num = l2.cancel_buy_strategy.SecondCancelBigNumComputer.compute_left_big_num(code,
                                                                                                  buy_single_index,
                                                                                                  buy_exec_index,
                                                                                                  total_data[-1][
                                                                                                      "index"],
                                                                                                  total_data,
                                                                                                  0, min_money_w)
            if left_big_num > 0:
                # 重新获取分数与分数索引
                limit_up_time = limit_up_time_manager.get_limit_up_time(code)
                if limit_up_time is None:
                    limit_up_time = tool.get_now_time_str()
                score = first_code_score_manager.get_score(code, cls.volume_rate_info[code][0], limit_up_time, True,
                                                           left_big_num)
                cls.__l2PlaceOrderParamsManagerDict[code].set_score(score)
        logger_place_order_score.info("code={},data='score_index':{},'score_info':{}", code,
                                      cls.__l2PlaceOrderParamsManagerDict[code].score_index,
                                      cls.__l2PlaceOrderParamsManagerDict[code].score_info)
        if not gpcode_manager.WantBuyCodesManager.is_in(code):
            # 查看分数等级
            score_index = cls.__l2PlaceOrderParamsManagerDict[code].score_index
            score = cls.__l2PlaceOrderParamsManagerDict[code].score
            score_info = cls.__l2PlaceOrderParamsManagerDict[code].score_info
            zyltgb = global_util.zyltgb_map.get(code)
            if zyltgb is None:
                global_data_loader.load_zyltgb()
                zyltgb = global_util.zyltgb_map.get(code)
            # 区分大票,小票
            if zyltgb >= 80 * 100000000:
                if cls.volume_rate_info[code][0] < 0.5:
                    return False, True, f"大市值:量大于50%才下单,量比:{cls.volume_rate_info[code][0]}"
            elif zyltgb <= 35 * 100000000:
                # 获取板块中的票的数量
                if score_info[1][5]["limit_up_codes_count"] < 2:
                    return False, True, f"小市值:板块中必须2个涨停才能买,板块{score_info[1][5]['target_block_info'][0]}-涨停数{score_info[1][5]['limit_up_codes_count']}"
            # 尾盘偷跑票
            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 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)
l2/l2_data_util.py
@@ -175,7 +175,7 @@
    count = data["count"]
    data = data["data"]
    # 获取涨停价
    return day, client, channel, code, capture_time, process_time, data,count
    return day, client, channel, code, capture_time, process_time, data, count
# 元数据是否有差异
@@ -453,6 +453,10 @@
                return new_index_list[start_index], new_index_list[start_index:start_index + len(queues)]
            return None, None
        # 3个数据以上的不需要判断最近的一次未涨停时间
        if len(queueList) >= 3:
            latest_not_limit_up_time = None
        # 判断匹配的位置是否可信
        def is_trust(indexes):
            cha = []
l2/l2_log.py
@@ -1,9 +1,9 @@
from log import logger_l2_trade_cancel, logger_l2_trade_buy, logger_l2_trade
from log import logger_l2_trade_cancel, logger_l2_trade_buy, logger_trade_record, logger_l2_trade
threadIds = {}
def debug( code, content, *args):
def debug(code, content, *args):
    logger_l2_trade.debug(("thread-id={} code={}  ".format(threadIds.get(code), code) + content).format(*args))
@@ -15,3 +15,9 @@
def cancel_debug(code, content, *args):
    logger_l2_trade_cancel.debug(
        ("thread-id={} code={}  ".format(threadIds.get(code), code) + content).format(*args))
# 交易记录
def trade_record(code, type, content, *args):
    logger_trade_record.debug(
        ("thread-id={} code={} type={} data=".format(threadIds.get(code), code, type) + content).format(*args))
l2_data_util.py
@@ -41,7 +41,13 @@
        else:
            return False
# 获取大资金的金额
def get_big_money_val(limit_up_price):
    if limit_up_price > 3.0:
        return 300 * 10000
    else:
        max_money = limit_up_price * 10000
        return max_money * 0.95
# if int(val["num"]) >= constant.BIG_MONEY_NUM:
l2_trade_test.py
@@ -85,9 +85,9 @@
                except Exception as e:
                    pass
    @unittest.skip("跳过此单元测试")
    # @unittest.skip("跳过此单元测试")
    def test_trade(self):
        code = "002524"
        code = "603843"
        clear_trade_data(code)
        l2.l2_data_util.load_l2_data(code)
        total_datas = deepcopy(l2.l2_data_util.local_today_datas[code])
@@ -119,8 +119,8 @@
        l2.l2_data_util.local_today_num_operate_map[code].clear()
        print("id:", id(l2.l2_data_util.local_today_datas))
        safe_count_manager.BuyL2SafeCountManager.get_safe_count = mock.Mock(return_value=16)
        l2_trade_factor.L2TradeFactorUtil.compute_m_value = mock.Mock(return_value=(14699952, ""))
        # safe_count_manager.BuyL2SafeCountManager.get_safe_count = mock.Mock(return_value=16)
        # l2_trade_factor.L2TradeFactorUtil.compute_m_value = mock.Mock(return_value=(14699952, ""))
        # pos_list.insert(41,(225,306))
        # pos_list.insert(63, (345, 423))
        # pos_list.insert(66, (440, 447))
log.py
@@ -106,6 +106,10 @@
                   filter=lambda record: record["extra"].get("name") == "buy_1_volumn_record",
                   rotation="00:00", compression="zip", enqueue=True)
        logger.add(self.get_path("ths", "trade_queue_price_info"),
                   filter=lambda record: record["extra"].get("name") == "trade_queue_price_info",
                   rotation="00:00", compression="zip", enqueue=True)
        logger.add(self.get_path("ths", "day_volumn"),
                   filter=lambda record: record["extra"].get("name") == "day_volumn",
                   rotation="00:00", compression="zip", enqueue=True)
@@ -122,8 +126,12 @@
                   filter=lambda record: record["extra"].get("name") == "debug",
                   rotation="00:00", compression="zip", enqueue=True)
        logger.add(self.get_path("score", "buy_score"),
                   filter=lambda record: record["extra"].get("name") == "buy_score",
        logger.add(self.get_path("trade", "trade_record"),
                   filter=lambda record: record["extra"].get("name") == "trade_record",
                   rotation="00:00", compression="zip", enqueue=True)
        logger.add(self.get_path("score", "place_order_score"),
                   filter=lambda record: record["extra"].get("name") == "place_order_score",
                   rotation="00:00", compression="zip", enqueue=True)
    def get_path(self, dir_name, log_name):
@@ -163,6 +171,8 @@
logger_buy_1_volumn_record = __mylogger.get_logger("buy_1_volumn_record")
logger_trade_queue_price_info = __mylogger.get_logger("trade_queue_price_info")
logger_day_volumn = __mylogger.get_logger("day_volumn")
logger_buy_win_distibute = __mylogger.get_logger("buy_win_distibute")
@@ -171,8 +181,9 @@
logger_debug = __mylogger.get_logger("debug")
logger_buy_score = __mylogger.get_logger("buy_score")
logger_trade_record = __mylogger.get_logger("trade_record")
logger_place_order_score = __mylogger.get_logger("place_order_score")
class LogUtil:
    @classmethod
@@ -361,16 +372,16 @@
def export_logs(code):
    code_name = gpcode_manager.get_code_name(code)
    date = "2023-03-20"  # 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", "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}"
        if log_name == "l2_process" or log_name == "l2_process_time" or log_name == "cancel/h_cancel":
        if log_name == "l2_process" or log_name == "l2_process_time" or log_name == "cancel/h_cancel" or log_name == "l2_trade_buy_progress":
            key = code
        target_path = f"{target_dir}/{log_name}.{code}_{code_name}.{date}.log"
        # 创建文件夹
@@ -380,25 +391,44 @@
        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:
        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]
                index_set.add(int(index))
    results = list(index_set)
    results.sort()
    return results
# 加载买入得分记录
def load_buy_score_recod(code):
    path = f"D:/logs/gp/score/buy_score.{tool.get_now_date_str()}.log"
    path = f"D:/logs/gp/trade/trade_record.{tool.get_now_date_str()}.log"
    fdatas = []
    with open(path, 'r', encoding="utf-8") as f:
        lines = f.readlines()
        for line in lines:
            data_index = line.find("{}:".format(code))
            if data_index > 0:
                data_index = line.find(":", data_index)
                time_str = line[10:19]
                line = line[data_index + 1:]
                fdatas.append((time_str, eval(line)))
    if os.path.exists(path):
        with open(path, 'r', encoding="utf-8") as f:
            lines = f.readlines()
            for line in lines:
                data_index = line.find(f"code={code}")
                if data_index > 0:
                    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+"}")))
    return fdatas
if __name__ == '__main__':
    load_buy_score_recod("002213")
    print(logger_place_order_score.info("002681"))
    # logger_l2_h_cancel.info("test")
    # logger_l2_process_time.info("test123")
    # logger_buy_score.info("测试")
ocr/ocr_util.py
@@ -9,7 +9,7 @@
# 图像识别类
class OcrUtil:
    __ocr = CnOcr()
    reader = easyocr.Reader(['ch_sim','en'], gpu=False)
    reader = easyocr.Reader(['ch_sim', 'en'], gpu=False)
    @classmethod
    def ocr(cls, mat):
output/code_info_output.py
@@ -6,7 +6,11 @@
# 下单参数信息
# 选股宝
# 市场热度
import os
import sys
import code_volumn_manager
import constant
import global_data_loader
import global_util
import gpcode_manager
@@ -16,69 +20,82 @@
import tool
from l2 import l2_data_manager, l2_data_util, transaction_progress, l2_data_manager_new, code_price_manager
from third_data import hot_block_data_process
from trade import first_code_score_manager, l2_trade_factor
from trade import first_code_score_manager, l2_trade_factor, trade_manager, l2_trade_util
from trade.l2_trade_factor import L2TradeFactorUtil
import trade.deal_big_money_manager
base_output_content = {}
def __get_base_html_content():
    print("路径", sys.path[0])
    if base_output_content.get('css') is None:
        __base_html_content = ""
        with open("./output/css/style.css", mode='r') as f:
            lines = f.readlines()
            for line in lines:
                __base_html_content += line
        base_output_content['css'] = __base_html_content
    return f"<head><style>{base_output_content['css']}</style></head>"
def __format_data(code_info, score_info, buy_params_info, xgb_code_info, xgb_infos, codes_score, trade_info):
    html = ""
    html += f"<h2>{code_info[1]} {code_info[0]}</h2><br>"
    html = __get_base_html_content()
    html += "<body>"
    html += f"<h2>{code_info[1]} {code_info[0]}    ({code_info[2]})</h2><br>"
    if score_info:
        html += "<b>-----买前评分-------</b><br>"
        score_types = ["换手量能", "竞价强度", "资金力度", "日线形态", "历史股性", "板块热度", "上板时间", "市值大小", "股价大小"]
        html += "<table style='font-size:25px'>"
        html += "<table>"
        for i in range(0, len(score_info[1])):
            html += f"<tr><td>{score_types[i]}</td><td>{score_info[1][i]}</td><td>{score_info[2][i]}</td></tr>"
        html += f"<tr><td><b>评分求和:</td><td>{score_info[0]}</b></td><td></td></tr>"
        html += f"</table><br>"
    html += "\n"
    if buy_params_info:
        html += "<b><br>-----交易参数-------<br></b><table>"
        titles = ["买入意愿", "安全笔数", "动态M值", "买前大单", "成交进度", "买入信号", "买入执行位"]
        for i in range(0, len(titles)):
            html += f"<tr><td>{titles[i]}:</td><td>{buy_params_info[i]}</td></tr>"
        html += "</table><br>"
    html += "\n"
    if xgb_code_info:
        html += "<b><br>-----选股宝---------<br></b>"
        xgb_code_info_dates = ["今天", "昨天", "前天", "之前"]
        for i in range(0, len(xgb_code_info)):
            html += f"{xgb_code_info_dates[i]}:<br>"
            if xgb_code_info[i]:
                html += f"{xgb_code_info_dates[i]}:<br>"
                for info in xgb_code_info[i]:
                    if i == 0:
                        html += f"【<font color='red'>{info[0]}</font>】,共【<font color='red'>{info[1]}</font>】只票涨停<br>第【<font color='red'>{info[2]}</font>】涨停,现价【<font color='red'>{info[3]}</font>】元,涨幅【<font color='red'>{info[4]}</font>】<br><br>"
                    else:
                        html += f"【{info[0]}】,共【{info[1]}】只票涨停<br>第【{info[2]}】涨停,现价【{info[3]}】元,涨幅【{info[4]}】<br><br>"
            else:
                html += f"无<br>"
    html += "\n"
    if codes_score[0]:
        html += "<b>-----主动买入-------</b><br>"
        html += "<table>"
        for i in range(0, len(codes_score[0])):
            if i % 4 == 0:
            if i % 3 == 0:
                html += "<tr>"
            html += f"<td><font color='red'>{codes_score[0][i][1]}:{codes_score[0][i][2]}</font></td>"
            if i % 4 == 3 or i == len(codes_score[0]) - 1:
            html += f"<td><font color='red'>{'*' if codes_score[0][i][3] else ''}{codes_score[0][i][1]}({codes_score[0][i][0]}):{codes_score[0][i][2]}</font></td>"
            if i % 3 == 2 or i == len(codes_score[0]) - 1:
                html += "</tr>"
        html += "</table><br>"
        html += "</table><br>\n"
    if codes_score[1]:
        html += "<b>-----被动买入-------</b><br>"
        html += "<table>"
        for i in range(0, len(codes_score[1])):
            if i % 4 == 0:
            if i % 3 == 0:
                html += "<tr>"
            html += f"<td><font color='#000080'>{codes_score[1][i][1]}:{codes_score[1][i][2]}</font></td>"
            if i % 4 == 3 or i == len(codes_score[1]) - 1:
            html += f"<td><font color='#000080'>{'*' if codes_score[1][i][3] else ''}{codes_score[1][i][1]}({codes_score[1][i][0]}):{codes_score[1][i][2]}</font></td>"
            if i % 3 == 2 or i == len(codes_score[1]) - 1:
                html += "</tr>"
        html += "</table><br>"
        html += "</table><br>\n"
    if codes_score[2]:
    if codes_score[2] and False:
        html += "<b>-----不买入-------</b><br>"
        html += "<table>"
        for i in range(0, len(codes_score[2])):
@@ -87,12 +104,12 @@
            html += f"<td>{codes_score[2][i][1]}:{codes_score[2][i][2]}</td>"
            if i % 4 == 3 or i == len(codes_score[1]) - 1:
                html += "</tr>"
        html += "</table><br>"
        html += "</table><br>\n"
    if trade_info:
        html += "<b>-----今日挂撤记录-------</b><br>"
        html += "<br>今日是否炸板:"
        if trade_info[0]:
        if trade_info[0] is not None:
            html += f"炸板-{trade_info[0]}"
        else:
            html += f"未炸板"
@@ -101,28 +118,42 @@
            for i in range(0, len(trade_info[1])):
                if i % 2 == 0:
                    html += "<tr>"
                html += f"<td>第{i + 1}次下单 评分{trade_info[1][i][1][0][0]} {trade_info[1][i][0]} </td>"
                html += f"<td>{trade_info[1][i]}</td>"
                if i % 2 == 1 or i == len(codes_score[0]) - 1:
                    html += "</tr>"
            html += "</table><br>"
        html += "<br>"
        html += "<br>\n"
    if xgb_infos:
        html += "<b><br>-----市场热度-------<br></b><table>"
        for info in xgb_infos:
            html += f"<tr><td><font size='3'>{info[0]}</font><br><div style='margin-left:100px;'>{info[1]}</div></td></tr>"
        html += "</tr>"
            html += f"<tr><td>{info[0]}<br><div style=''>{info[1]}</div></td></tr>"
        html += "</table>"
    html += "<br><br>"
    html += "</body>"
    return html
def get_output_html(code):
    day = tool.get_now_date_str()
    is_target_code = gpcode_manager.FirstCodeManager.is_in_first_record(code)
    code_info = [code, gpcode_manager.get_code_name(code)]
    code_extra_infos=[]
    if l2_trade_util.BlackListCodeManager.is_in(code):
        code_extra_infos.append("黑名单")
    if l2_trade_util.WhiteListCodeManager.is_in(code):
        code_extra_infos.append("白名单")
    # 获取白名单,黑名单
    if trade_manager. gpcode_manager.WantBuyCodesManager.is_in(code):
        code_extra_infos.append("想买单")
    code_info = [code, gpcode_manager.get_code_name(code),",".join(code_extra_infos)]
    score_info = None
    buy_params_info = None
    xgb_infos = None
    total_datas = l2_data_util.local_today_datas.get(code)
    if total_datas is None:
        l2_data_util.load_l2_data(code)
        total_datas = l2_data_util.local_today_datas.get(code)
    if is_target_code:
        limit_up_price = gpcode_manager.get_limit_up_price(code)
        limit_up_time = limit_up_time_manager.get_limit_up_time(code)
@@ -143,10 +174,7 @@
        # 竞价强度
        score_list_new.append(score_list[2])
        score_source_list_new.append(f"开盘啦今日委停【{score_source_list[2] if score_source_list[2] else 0}万】")
        total_datas = l2_data_util.local_today_datas.get(code)
        if total_datas is None:
            l2_data_util.load_l2_data(code)
            total_datas = l2_data_util.local_today_datas.get(code)
        # 资金力度
        deal_indexes = trade.deal_big_money_manager.get_traded_indexes(code)
        deal_info = ""
@@ -205,12 +233,17 @@
        for n in range(0, len(score_source_list[4])):
            if n == 0:
                if not score_source_list[4][n]:
                    nature_source.append("无涨停")
                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)}】")
                else:
                    nature_source.append("有涨停")
            if n == 1:
                nature_source.append(f"首板溢价率【{round(score_source_list[4][2],2)}】")
                    nature_source.append(f"无首板")
            elif n == 2:
                if score_source_list[4][n]:
                    nature_source.append(f"首板炸板溢价率【{round(score_source_list[4][n], 2)}】")
                else:
                    nature_source.append(f"无首板炸板")
        score_list_new.append(nature_score)
        score_source_list_new.append(",".join(nature_source))
@@ -220,14 +253,37 @@
        hot_block_source = []
        for k in score_list[5]:
            hot_block_score += k
        for n in range(0, len(score_source_list[5])):
            if n == 1:
                hot_block_source.append(f"【{score_source_list[5][0]}】共{score_source_list[5][n]}个涨停")
            elif n == 2:
                hot_block_source.append(f"共{score_source_list[5][n]}个炸板")
            elif n == 4:
                if score_source_list[5][n]:
                    hot_block_source.append(f"【{score_source_list[5][n][0][0]}】{score_source_list[5][n][1]}")
        hot_block_source_data = score_source_list[5]
        for k in hot_block_source_data:
            hot_block = {
                # 目标板块信息(板块名称,板块涨幅,历史板块出现次数)
                "target_block_info": ("无板块", 0, 0),
                # 涨停顺序
                "limit_up_index": 0,
                # 涨停代码数量
                "limit_up_codes_count": 0,
                # 板块代码涨幅信息
                "block_codes_rates_info": (0, 0),
                # 炸板代码数量
                "break_size": 0,
                # 炸板回封数量
                "re_limit_up_size": 0,
                # 高位版信息
                "high_block_infos": [],
            }
            if k == "block_codes_rates_info":
                hot_block_source.append(f"平均涨幅:【{round(hot_block_source_data[k][0]/hot_block_source_data[k][1],2)}%】")
            elif k == "limit_up_codes_count":
                hot_block_source.append(f"板块涨停数量:【{hot_block_source_data[k]}】")
            elif k == "target_block_info":
                hot_block_source.append(f"板块涨幅:【{hot_block_source_data[k][1]}%】")
            elif k == "limit_up_index":
                hot_block_source.append(f"第【{hot_block_source_data[k]+1}】只涨停")
            elif k == "high_block_infos":
                for info in hot_block_source_data[k]:
                    hot_block_source.append(f"{info[0][1]}{info[1]}")
            if k == "target_block_info":
                hot_block_source.append(f"【{hot_block_source_data[k][0]}】概念出现【{hot_block_source_data[k][2]}】次")
        score_list_new.append(hot_block_score)
        score_source_list_new.append(",".join(hot_block_source))
@@ -262,7 +318,16 @@
                                                                                      score_source_list))
        buy_params_info = []
        if -1 < __L2PlaceOrderParamsManager.score_index < 3:
            buy_params_info.append("<font color='red'>【主动买入】</font>")
            temp = "<font color='red'>【主动买入】"
            if __L2PlaceOrderParamsManager.score_index == 0:
                temp += "***"
            elif __L2PlaceOrderParamsManager.score_index == 1:
                temp += "**"
            else:
                temp += "*"
            temp += "</font>"
            buy_params_info.append(temp)
        elif __L2PlaceOrderParamsManager.score_index < 0:
            buy_params_info.append("【不执行买入】")
        else:
@@ -365,8 +430,8 @@
            # 获取板块中的代码
            block_codes_set = set()
            for d in block[2]:
                code = d[0][1].split(".")[0]
                block_codes_set.add(code)
                _code = d[0][1].split(".")[0]
                block_codes_set.add(_code)
            if codes:
                codes_data_html = "<table><tr>"
@@ -376,7 +441,7 @@
                        # 不是该板块数据
                        continue
                    count += 1
                    codes_data_html += "<td>"
                    codes_data_html += "<td style = 'text-decoration:underline;'>"
                    # 如果代码涨停时间或者没有在最新的代码中
                    if (len(code_data[2]) < 6 or code_data[0] not in block_codes_set) and len(code_data[3]) > 6:
                        # 炸板
@@ -390,38 +455,57 @@
                    if count % 4 == 0:
                        codes_data_html += "</tr><tr>"
                codes_data_html += "</tr></table>"
                xgb_infos.append((f"***【{block[0]}】,涨幅【{block[1]}】,共【{limit_up_count}】个涨停", codes_data_html))
                _info = (f"***【{block[0]}】,涨幅【{block[1]}】,共【{limit_up_count}】个涨停", codes_data_html)
                is_target_block = False
                if xgb_code_info:
                    for _code_info in xgb_code_info[0]:
                        if len(_code_info) > 0 and _code_info[0] == block[0]:
                            is_target_block = True
                            break
                if is_target_block:
                    xgb_infos.insert(0, _info)
                else:
                    xgb_infos.append(_info)
    codes_score = __load_codes_scores()
    trade_info = __load_trade_record(code)
    trade_info = __load_trade_record(code, total_datas)
    return __format_data(code_info, score_info, buy_params_info, xgb_code_info, xgb_infos, codes_score, trade_info)
def __load_codes_scores():
    # 获取所有监听中的代码
    codes = gpcode_manager.get_first_gp_codes()
    scores = l2_data_manager_new.L2TradeDataProcessor.get_code_scores()
    scores = {}  # l2_data_manager_new.L2TradeDataProcessor.get_code_scores()
    for code in codes:
        if code not in scores:
            # 获取分数
            limit_up_time = limit_up_time_manager.get_limit_up_time(code)
            if limit_up_time is None:
                continue
            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
            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
    # 筛选180分以上的代码
    scores_list = []
    for code in scores:
        code_name = gpcode_manager.get_code_name(code)
        scores_list.append((code, code_name, scores[code]))
        # 获取现价,判断是否涨停
        current_price_info = global_util.cuurent_prices.get(code)
        is_limit_up = True
        if current_price_info is not None and not current_price_info[1]:
            is_limit_up = False
        else:
            is_limit_up = True
        scores_list.append((code, code_name, scores[code], is_limit_up))
    scores_list.sort(key=lambda x: x[2], reverse=True)
    fscores_list = [[], [], []]
    for score in scores_list:
        if score[2] >= 180:
        if score[2] >= constant.BUY_SCORE_RANK_1:
            fscores_list[0].append(score)
        elif score[2] >= 100:
        elif score[2] >= constant.BUY_SCORE_RANK_0:
            fscores_list[1].append(score)
        else:
            fscores_list[2].append(score)
@@ -429,37 +513,55 @@
    return fscores_list
def __load_trade_record(code):
def __load_trade_record(code, total_datas):
    def format_l2_data(item):
        return f"{item['val']['time']}#{item['val']['num']}手#{round(item['val']['num'] * float(item['val']['price']) * 100 / 10000, 1)}万"
    # 获取炸板信息
    limit_up_info = code_price_manager.Buy1PriceManager.get_limit_up_info(code)
    break_time = limit_up_info[1]
    records = log.load_buy_score_recod(code)
    return break_time, records
    records =[]
    try:
        records = log.load_buy_score_recod(code)
    except:
        pass
    records_new = []
    index = 0
    if records:
        try:
            for record in records:
                time_ = record[0]
                type = record[1]
                data = record[2]
                if type == '下单':
                    index += 1
                    temp = f"第{index}次下单:【{time_}】&【{data['score']}分】,{data.get('desc')}"
                    records_new.append(temp)
                elif type == 'S撤':
                    # index':378 , 'rate':0.51 , 'target_rate':0.49
                    pass
                elif type == 'S撤范围':
                    start = format_l2_data(total_datas[data['start_index']])
                    end = format_l2_data(total_datas[data['end_index']])
                    range_seconds = data['range_seconds']
                    temp = f"第{index}次撤单:S撤囊括范围:【起始位:{start}】至【截止位:{end}】囊括时间【{range_seconds}】秒"
                elif type == 'H撤范围':
                    start = format_l2_data(total_datas[data['start_index']])
                    end = format_l2_data(total_datas[data['end_index']])
                    count = data['count']
                    temp = f"H撤囊括范围:【起始位:{start}】至【截止位:{end}】物理笔数共【{count}】笔"
                elif type == 'H撤':
                    # 'start_index':339,'end_index':464, 'count':17
                    pass
                elif type == '撤单':
                    temp = f"第{index}次撤单:【{time_}】{data['msg']}"
                    records_new.append(temp)
        except:
            pass
    return break_time, records_new
if __name__ == '__main__':
    code = "002410"
    day = '2023-03-27'
    xgb_datas = hot_block_data_process.XGBHotBlockDataManager.list_by_code(code, day)
    datas = []
    if xgb_datas:
        for data in xgb_datas:
            block = data[2]
            block_datas = hot_block_data_process.XGBHotBlockDataManager.list_by_block(block, day)
            block_datas = list(block_datas)
            limit_up_count = 0
            limit_up_time = None
            for d in block_datas:
                if len(d[4]) > 6:
                    limit_up_count += 1
                    if d[3] == code:
                        limit_up_time = d[4]
            # 根据涨停时间排序
            block_datas.sort(key=lambda d: (d[4] if len(d[4]) > 6 else '15:00:00'))
            for i in range(len(block_datas)):
                if block_datas[i][3] == code:
                    datas.append((block, limit_up_count, (i + 1) if limit_up_time is not None else (limit_up_count + 1),
                                  block_datas[i][5], block_datas[i][6]))
                    break
    st="8天3板"
    print(st[-2:-1])
output/css/style.css
New file
@@ -0,0 +1,12 @@
body{
    font-size: 14px;
}
h2{
    font-size:20px;
}
table tr td{
    font-size: 13px;
    padding-right: 20px;
}
server.py
@@ -22,6 +22,7 @@
import gpcode_manager
import authority
import juejin
import limit_up_time_manager
from l2 import l2_data_manager_new, l2_data_manager, l2_data_log, l2_log, code_price_manager
import l2_data_util
from l2.cancel_buy_strategy import HourCancelBigNumComputer, L2LimitUpMoneyStatisticUtil
@@ -34,7 +35,7 @@
from third_data import hot_block_data_process
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
    first_code_score_manager, current_price_process_manager
import l2_code_operate
from code_data_util import ZYLTGBUtil
import l2.transaction_progress
@@ -272,16 +273,17 @@
                        # 保存未筛选的首板代码
                        new_add_codes = gpcode_first_screen_manager.set_target_no_screen_codes(codes)
                        # 保存自由流通股本
                        zyltgb_list = []
                        for data in dataList:
                            code = data["code"]
                            if code in global_util.zyltgb_map:
                                continue
                            zyltgb_list.append(
                                {"code": code, "zyltgb": data["zyltgb"], "zyltgb_unit": data["zyltgbUnit"]})
                        if zyltgb_list:
                            ZYLTGBUtil.save_list(zyltgb_list)
                            global_data_loader.load_zyltgb()
                        if dataList:
                            zyltgb_list = []
                            for data in dataList:
                                code = data["code"]
                                if code in global_util.zyltgb_map:
                                    continue
                                zyltgb_list.append(
                                    {"code": code, "zyltgb": data["zyltgb"], "zyltgb_unit": data["zyltgbUnit"]})
                            if zyltgb_list:
                                ZYLTGBUtil.save_list(zyltgb_list)
                                global_data_loader.load_zyltgb()
                        bad_codes = set()
@@ -301,8 +303,8 @@
                                need_get_volumn = True
                            if need_get_volumn:
                                volumes_data = juejin.get_volumns_by_code(code, 150)
                                volumes = juejin.parse_max_volume(volumes_data[:60], code_nature_analyse.is_new_top(
                                    gpcode_manager.get_limit_up_price(code), volumes_data[:60]))
                                volumes = juejin.parse_max_volume(volumes_data[:90], code_nature_analyse.is_new_top(
                                    gpcode_manager.get_limit_up_price(code), volumes_data[:90]))
                                logger_first_code_record.info("{} 获取到首板60天最大量:{}", code, volumes)
                                code_volumn_manager.set_histry_volumn(code, volumes[0], volumes[1], volumes[2])
                                # 判断K线形态
@@ -330,6 +332,29 @@
                                if not gpcode_manager.is_in_gp_pool(lc):
                                    # 移除代码
                                    l2_code_operate.L2CodeOperate.get_instance().add_operate(0, lc, "代码被移除")
                        if new_add_codes:
                            # 低分值代码禁止交易
                            for code in new_add_codes:
                                try:
                                    score, score_list = first_code_score_manager.get_score(code, 0, None, False)
                                    if score < 0:
                                        trade_manager.ForbiddenBuyCodeByScoreManager.add_code(code)
                                    # elif score >= 200:
                                    #     # 如果没有涨停过
                                    #     limit_up_time = limit_up_time_manager.get_limit_up_time(code)
                                    #     if limit_up_time is None and int(tool.get_now_time_str().replace(":","")) > int("113000"):
                                    #         gpcode_manager.WantBuyCodesManager.add_code(code)
                                except Exception as e:
                                    logging.exception(e)
                        # if dataList and int(tool.get_now_time_str().replace(":","")) > int("113000"):
                        #     for data in dataList:
                        #         code = data["code"]
                        #         if gpcode_manager.WantBuyCodesManager.is_in(code):
                        #             score, score_list = first_code_score_manager.get_score(code, 0, None, False)
                        #             if score < 200:
                        #                 gpcode_manager.WantBuyCodesManager.remove_code(code)
                        # 保存现价
                        if dataList:
@@ -479,13 +504,17 @@
                        buy_time = data["buyTime"]
                        buy_one_price = data["buyOnePrice"]
                        buy_one_volumn = data["buyOneVolumn"]
                        sell_one_price = data["sellOnePrice"]
                        sell_one_volumn = data["sellOneVolumn"]
                        buy_queue = data["buyQueue"]
                        if buy_one_price is None:
                            print('买1价没有,', code)
                        limit_up_price = gpcode_manager.get_limit_up_price(code)
                        if limit_up_price is not None:
                            code_price_manager.Buy1PriceManager.process(code, buy_one_price, buy_time, limit_up_price)
                            code_price_manager.Buy1PriceManager.process(code, buy_one_price, buy_time, limit_up_price,
                                                                        sell_one_price, sell_one_volumn)
                            _start_time = time.time()
                            msg += "买1价格处理:" + f"{_start_time - __start_time} "
@@ -602,7 +631,7 @@
                            volumn = item["volume"]
                            volumnUnit = item["volumeUnit"]
                            code_volumn_manager.save_today_volumn(item["code"], volumn, volumnUnit)
                        juejin.accept_prices(datas)
                        current_price_process_manager.accept_prices(datas)
                elif type == 50:
                    data = data_process.parse(_str)["data"]
                    if data is not None:
@@ -756,14 +785,29 @@
                    # 加入白名单
                    data = json.loads(_str)
                    codes = data["data"]["codes"]
                    for code in codes:
                        l2_trade_util.WhiteListCodeManager.add_code(code)
                        name = gpcode_manager.get_code_name(code)
                        if not name:
                            results = juejin.JueJinManager.get_gp_codes_names([code])
                            if results:
                                gpcode_manager.CodesNameManager.add_first_code_name(code, results[code])
                    return_str = json.dumps({"code": 0})
                    try:
                        for code in codes:
                            # 自由流通市值>50亿,股价高于30块的不能加白名单
                            limit_up_price = gpcode_manager.get_limit_up_price(code)
                            if float(limit_up_price) > 30:
                                raise Exception("股价高于30元")
                            # zyltgb = global_util.zyltgb_map.get(code)
                            # if zyltgb is None:
                            #     global_data_loader.load_zyltgb()
                            #     zyltgb = global_util.zyltgb_map.get(code)
                            # if zyltgb > 50 * 100000000:
                            #     raise Exception("自由流通股本大于50亿")
                            l2_trade_util.WhiteListCodeManager.add_code(code)
                            name = gpcode_manager.get_code_name(code)
                            if not name:
                                results = juejin.JueJinManager.get_gp_codes_names([code])
                                if results:
                                    gpcode_manager.CodesNameManager.add_first_code_name(code, results[code])
                        return_str = json.dumps({"code": 0})
                    except Exception as e:
                        return_str = json.dumps({"code": 1, "msg": str(e)})
                elif type == 203:
                    # 移除黑名单
                    data = json.loads(_str)
@@ -826,6 +870,9 @@
                    else:
                        trade_manager.TradeStateManager.close_buy()
                    return_str = json.dumps({"code": 0, "msg": ("开启成功" if is_open else "关闭成功")})
                elif type == 502:
                    can_buy = trade_manager.TradeStateManager.is_can_buy()
                    return_str = json.dumps({"code": 0, "data": {"can_buy": can_buy}})
                sk.send(return_str.encode())
@@ -920,7 +967,7 @@
    for code in codes:
        try:
            global_data_loader.load_zyltgb()
            limit_up_price =  float(gpcode_manager.get_limit_up_price(code))
            limit_up_price = float(gpcode_manager.get_limit_up_price(code))
            volumes_data = juejin.get_volumns_by_code(code, 150)
            volumes_data = volumes_data[1:]
            volumes = juejin.parse_max_volume(volumes_data[:60],
third_data/hot_block.py
@@ -92,6 +92,7 @@
    client.connect(ip_port)
    data = {"type": 70, "day": day, "data": datas}
    client.send(json.dumps(data).encode("gbk"))
    result = client.recv(1024)
    client.close()
third_data/hot_block_data_process.py
@@ -10,8 +10,10 @@
from db import mysql_data
import limit_up_time_manager
import gpcode_manager
from l2 import code_price_manager
__redisManager = redis_manager.RedisManager(0)
INVALID_BLOCKS = ["其他", "ST股", "ST摘帽", "业绩增长", "业绩预增", "公告", "次新股"]
def __get_redis():
@@ -25,7 +27,7 @@
    @classmethod
    def save(cls, day, datas):
        cls.latest_datas = datas
        mysqldb = mysql_data.Mysqldb()
        # 统计代码所属板块
        code_block_dict = {}
@@ -36,6 +38,26 @@
                    code_block_dict[code] = set()
                code_block_dict[code].add(data[0])
        # 如果本次和上次相差的代码且之前有过涨停就判断为炸板
        if cls.latest_datas:
            latest_codes = set()
            for data in cls.latest_datas:
                for code_info in data[2]:
                    code = code_info[0][1].split(".")[0]
                    latest_codes.add(code)
            now_codes = set(code_block_dict.keys())
            del_set = latest_codes - now_codes
            for code in del_set:
                # 获取之前是否涨停过
                results = cls.list_by_code(code, tool.get_now_date())
                if results:
                    first_limit_up_time = results[0][8]
                    if len(first_limit_up_time) > 6:
                        # 之前涨停过,更新炸板时间
                        for result in results:
                            mysqldb.execute(
                                f"update xgb_hot_block set _open_limit_up_time='{tool.get_now_time_str()}',_update_time=now() where _id='{result[0]}'")
        cls.latest_datas = datas
        for data in datas:
            for code_info in data[2]:
                code = code_info[0][1].split(".")[0]
@@ -45,6 +67,11 @@
                limit_up_time = code_info[4]
                if len(limit_up_time) <= 6:
                    limit_up_time = ''
                # 00/60开头代码 有涨停时间
                if code.find("00") == 0 or code.find("60") == 0:
                    if len(limit_up_time) > 6:
                        code_price_manager.Buy1PriceManager.set_limit_up_time(code, limit_up_time)
                if not result:
                    mysqldb.execute(
                        f"insert into xgb_hot_block(_id,_day,_block_name,_code,_limit_up_time,_price,_rate,_update_time,_first_limit_up_time,_code_name) values('{_id}','{day}','{data[0]}','{code}','{code_info[4]}','{code_info[2]}','{code_info[3]}',now(),'{limit_up_time}','{code_info[0][0]}')")
@@ -54,9 +81,9 @@
                        mysqldb.execute(
                            f"update xgb_hot_block set _limit_up_time='{code_info[4]}',_price='{code_info[2]}',_rate='{code_info[3]}',_update_time=now(),_code_name='{code_info[0][0]}' where _id='{_id}'")
                        if (not result[8] or len(result[8]) <= 6) and len(limit_up_time) >= 6:
                            # 没有首次涨停时间
                            mysqldb.execute(
                                f"update xgb_hot_block set _first_limit_up_time='{limit_up_time}',_update_time=now() where _id='{_id}'")
                cls.__last_datas[_id] = code_info
                # 获取原来的代码所属板块,删除之前错误的板块
                old_datas = XGBHotBlockDataManager.list_by_code(code, day)
@@ -83,18 +110,27 @@
        return mysqldb.select_all(f"select * from xgb_hot_block where _block_name='{block_name}' and _day='{day}'")
    @staticmethod
    def list_blocks(days):
    def list_blocks_with_day(days):
        mysqldb = mysql_data.Mysqldb()
        sql = "select distinct(_block_name) from xgb_hot_block where "
        sql = "select _block_name,_day from xgb_hot_block where "
        wheres = []
        for day in days:
            wheres.append(f"_day = '{day}'")
        sql += " or ".join(wheres)
        sql += " group by _block_name,_day"
        results = mysqldb.select_all(sql)
        fresult = set()
        for result in results:
            fresult.add(result[0])
        return fresult
        return results
    @staticmethod
    def get_latest_blocks(code):
        wheres = []
        for b in INVALID_BLOCKS:
            wheres.append(f"hb.`_block_name` != '{b}'")
        wheres = " and ".join(wheres)
        sql = f"SELECT GROUP_CONCAT(_block_name) FROM (SELECT hb.`_block_name`,hb.`_day` FROM `xgb_hot_block` 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"
        mysqldb = mysql_data.Mysqldb()
        return mysqldb.select_one(sql)
class XGBDataUtil:
@@ -128,49 +164,76 @@
    start_date = start_date.strftime("%Y-%m-%d")
    days = juejin.JueJinManager.get_trading_dates(start_date, end_date)
    days = days[0 - day_count:]
    results = XGBHotBlockDataManager.list_blocks(days)
    results = XGBHotBlockDataManager.list_blocks_with_day(days)
    __blocks_dict[now_day] = results
    return results
# 加载之前的板块
__before_block_dict = {}
def __load_before_block(code):
    if code not in __before_block_dict:
        blocks = XGBHotBlockDataManager.get_latest_blocks(code)
        if blocks:
            blocks = blocks[0].split(',')
            __before_block_dict[code] = blocks
    return __before_block_dict.get(code)
def __get_code_from_code_info(code_info):
    code = code_info[0][1].split(".")[0]
    return code
# 获取代码所在板块信息
def get_info(code):
    blocks = get_code_blocks(code)
    # 判断是否有新概念
    # 新概念
    new_block = None
    latest_blocks = get_latest_block(15)
    if blocks:
        for block in blocks:
            if block not in latest_blocks:
                new_block = block
                break
                # # 如果板块中的涨停票数》=2才算新题材,暂时取消
                # count = 0
                # if XGBHotBlockDataManager.latest_datas:
                #     for b in XGBHotBlockDataManager.latest_datas:
                #         if b[0] == new_block:
                #             for code_data in b[2]:
                #                 if len(code_data[4]) > 6:
                #                     count += 0
                # if count < 1:
                #     # 板块中最低有
                #     new_block = None
                # if not new_block:
                # break
    if not blocks:
        blocks = __load_before_block(code)
    latest_blocks_info = get_latest_block(15)
    # 统计板块出现次数
    # 获取目标板块
    target_block = None
    if blocks:
        for block in blocks:
            if block == '公告' or block == '其他':
            if block in INVALID_BLOCKS:
                continue
            target_block = block
            break
    if not target_block:
        return None
    # 统计板块中的平均涨幅
    total_rates = 0
    total_count = 0
    target_block_rate = 0
    if XGBHotBlockDataManager.latest_datas:
        for b in XGBHotBlockDataManager.latest_datas:
            if b[0] != target_block:
                continue
            if b[1]:
                target_block_rate = float(b[1].strip().replace("%", ''))
            for code_info in b[2]:
                code__ = __get_code_from_code_info(code_info)
                rate = float(code_info[3].strip().replace("%", ''))
                if code__ != code:
                    total_rates += rate
                    total_count += 1
    # 统计板块出现的次数
    target_block_histry_count = 0
    if blocks:
        for block_info in latest_blocks_info:
            if block_info[0] != target_block:
                continue
            target_block_histry_count += 1
    # 是否出现过高位板
    high_block_info = None
    high_block_infos = []
    for block in blocks:
        if block == '公告' or block == '其他':
            continue
@@ -178,19 +241,39 @@
            has_high, high_code_info = XGBDataUtil.is_has_high_code(block, XGBHotBlockDataManager.latest_datas)
            if has_high:
                high_block_info = (high_code_info[0], high_code_info[1])
                high_block_infos.append(high_block_info)
    limit_up_codes_set = set()
    limit_up_codes_info_set = set()
    # 板块下的代码数量
    block_codes_set = set()
    if XGBHotBlockDataManager.latest_datas:
        for block in XGBHotBlockDataManager.latest_datas:
            if block[0] == target_block:
                for code_data in block[2]:
                    code_ = code_data[0][1].split('.')[0]
                    if len(code_data[4]) > 6:
                        limit_up_codes_set.add(code_data[0][1].split('.')[0])
                        limit_up_codes_info_set.add((code_, code_data[4]))
                        block_codes_set.add(code_)
    # 获取涨停的顺序
    limit_up_index = -1
    limit_up_codes_info_list = list(limit_up_codes_info_set)
    limit_up_codes_info_list.sort(key=lambda x: x[1])
    for i in range(0, len(limit_up_codes_info_list)):
        if limit_up_codes_info_list[i][0] == code:
            limit_up_index = i
    if limit_up_index < 0:
        limit_up_index = len(limit_up_codes_info_list)
    # 涨停代码集合
    limit_up_codes_set = set([k[0] for k in limit_up_codes_info_list])
    limit_up_codes_set.discard(code)
    limit_up_count = len(limit_up_codes_set)
    block_codes_set.discard(code)
    limit_up_codes_count = len(block_codes_set)
    total_datas = XGBHotBlockDataManager.total_datas
    break_codes = set()
    re_limit_codes = set()
    for data in total_datas:
        block = data[2]
        if block != target_block:
@@ -198,15 +281,39 @@
        code = data[3]
        limit_up_time = data[4]
        first_limit_up_time = data[8]
        open_limit_up_time = data[10]
        if len(limit_up_time) <= 6 and first_limit_up_time and len(first_limit_up_time) > 6:
            break_codes.add(code)
        if len(limit_up_time) > 6 and open_limit_up_time and len(open_limit_up_time) > 6:
            re_limit_codes.add(code)
    # 排除自己
    break_codes.discard(code)
    # 排除已经涨停的代码
    break_codes = break_codes.difference(limit_up_codes_set)
    # 炸板个数
    break_size = len(break_codes)
    return target_block, limit_up_count, break_size, new_block, high_block_info
    # 炸板回封数量
    re_limit_up_size = len(re_limit_codes)
    fresult = {
        # 目标板块信息(板块名称,板块涨幅,历史板块出现次数)
        "target_block_info": (target_block, target_block_rate, target_block_histry_count),
        # 涨停顺序
        "limit_up_index": limit_up_index,
        # 涨停代码数量
        "limit_up_codes_count": limit_up_codes_count,
        # 板块代码涨幅信息
        "block_codes_rates_info": (total_rates, total_count),
        # 炸板代码数量
        "break_size": break_size,
        # 炸板回封数量
        "re_limit_up_size": re_limit_up_size,
        # 高位版信息
        "high_block_infos": high_block_infos,
    }
    return fresult
# 保存数据
@@ -269,5 +376,4 @@
if __name__ == "__main__":
    # XGBHotBlockDataManager.total_datas=XGBHotBlockDataManager.list_all("2023-03-23")
    # get_info('002230')
    print(get_latest_block())
    print(get_latest_block())
    print(__load_before_block("603163"))
third_data/kpl_util.py
@@ -1,3 +1,6 @@
import json
def parse_kpl_datas(results):
    start_y = -1
    end_x = -1
@@ -23,3 +26,54 @@
            fdatas.append((temp[2][:6], temp[1]))
            temp = []
    return fdatas
# 涨停代码:
# (代码,名称,首次涨停时间,最近涨停时间,几板,涨停原因,板块,实际流通,主力净额)
# (0,1,6,25,9,16,11,15,12)
# 竞价代码:
# (代码,名称,涨停委买额,板块,竞价成交额,实际流通)
# (0,1,18,11,22,15)
# 炸板:
# (代码,名称,涨幅,板块,实际流通)
# (0,1,4,11,15)
# 跌停:
# (代码,名称,板块,实际流通)
# (0,1,11,15)
# 曾跌停:
# (代码,名称,涨幅,板块,实际流通)
# (0,1,4,11,15)
TYPE_BIDDING = 8
TYPE_LIMIT_UP = 1
TYPE_OPEN_LIMIT_UP = 2
TYPE_LIMIT_DOWN = 3
TYPE_EVER_LIMIT_DOWN = 5
def __parseItemData(data, type):
    if type == TYPE_BIDDING:
        return data[0], data[1], data[18], data[11], data[22], data[15]
    elif type == TYPE_LIMIT_UP:
        return data[0], data[1], data[6], data[25], data[9], data[16], data[11], data[15], data[12]
    elif type == TYPE_OPEN_LIMIT_UP:
        return data[0], data[1], data[4], data[11], data[15]
    elif type == TYPE_LIMIT_DOWN:
        return data[0], data[1], data[11], data[15]
    elif type == TYPE_EVER_LIMIT_DOWN:
        return data[0], data[1], data[4], data[11], data[15]
    return None
def parseData(data, type):
    data = json.loads(data)
    if data["errcode"] != 0:
        raise Exception(f"解析数据出错,errcode:{data['errcode']}")
    list_ = data["list"]
    fresult_ = []
    for d in list_:
        pdata = __parseItemData(d, type)
        if pdata:
            fresult_ .append(pdata)
    return fresult_
third_data/res/kpl.txt
New file
@@ -0,0 +1,62 @@
static function OnBeforeRequest(oSession: Session) {
        if(oSession.fullUrl.Contains("https://apphis.longhuvip.com/w1/api/index.php")){
            var requestBody = oSession.GetRequestBodyAsString();
            if(requestBody&&requestBody.Contains("&st=30")){
                oSession.utilReplaceInRequest("&st=30", "&st=100");
                FiddlerObject.log("页码替换为100");
            }
        }
}
static function OnBeforeResponse(oSession: Session) {
        if (m_Hide304s && oSession.responseCode == 304) {
            oSession["ui-hide"] = "true";
        }
        if(oSession.fullUrl.Contains("https://apphis.longhuvip.com/w1/api/index.php")){
            var requestBody = oSession.GetRequestBodyAsString();
            var a;
            var pidType;
            var index;
            var day;
            if(requestBody){
                var ps = requestBody.Split("&");
                for(var p in ps){
                    if(ps[p].Contains("a=")){
                        a = ps[p].Replace("a=","");
                    }
                    else if(ps[p].Contains("PidType=")){
                        pidType = ps[p].Replace("PidType=","");
                    }
                    else if(ps[p].Contains("Index=")){
                        index = ps[p].Replace("Index=","");
                    }else if(ps[p].Contains("Day=")){
                        day = ps[p].Replace("Day=","");
                    }
                }
            }
            FiddlerObject.log("a:"+a+" pidType:"+pidType +" index:"+index);
            if(a){
                var responseStringOriginal = oSession.GetResponseBodyAsString();
                var fso;
                var file;
                fso = new ActiveXObject("Scripting.FileSystemObject");
                //文件保存路径,可自定义
                //第二个参数含义:1=ForReading(以只读方式打开),2=ForWriting (以写方式打开),8=ForAppending(以添加方式打开,写入的内容将添加到文件末尾)
                if(parseInt(index)==0)
                {
                    file = fso.OpenTextFile("D:/kpl/"+day+"_"+a+"_"+pidType+".log",2 ,true, true);
                }else{
                    file = fso.OpenTextFile("D:/kpl/"+day+"_"+a+"_"+pidType+".log",8 ,true, true);
                }
                file.writeLine(responseStringOriginal);
                file.close();
            }
        }
    }
third_data/xgb.py
New file
@@ -0,0 +1,57 @@
import json
import time
from datetime import datetime
import requests
import juejin
from third_data import hot_block
def get_data(day):
    url = f"https://flash-api.xuangubao.cn/api/surge_stock/stocks?date={day.replace('-', '')}&normal=true&uplimit=true"
    result = requests.get(url)
    result = result.content.decode('utf-8')
    result = json.loads(result)
    if result['code'] != 20000:
        raise Exception("获取失败")
    items = result["data"]["items"]
    block_codes = {}
    for item in items:
        # 代码名称,几天几板,现价,涨幅,涨停时间,换手,自由市值
        data = [(item[1], item[0]), item[11], item[2], item[3], item[6], item[10], item[4]]
        # 转换格式
        data[3] = f"{'+' if data[3] > 0 else '-'}" + f"{round(data[3] * 100,2)}%"
        if data[4] > 0:
            data[4] = datetime.fromtimestamp(data[4]).strftime("%H:%M:%S")
        else:
            data[4] = '--'
        data[5] = f"{round(data[5] * 100, 2)}%"
        data[6] = f"{round(data[6] / 100000000, 2)}亿"
        blocks = []
        for b in item[8]:
            blocks.append(b['name'])
        for b in blocks:
            if b not in block_codes:
                block_codes[b] = []
            block_codes[b].append(data)
    return block_codes
if __name__ == '__main__':
    date = '2022-07-22'
    for i in range(100):
        date = juejin.JueJinManager.get_previous_trading_date(date)
        print(date)
        results = get_data(date)
        fresults = []
        for key in results:
            #print("--------",key)
            #for data in results[key]:
            #    print(data)
            fresults.append((key,None,results[key]))
        print(fresults)
        hot_block.upload_data(date,fresults)
        time.sleep(5)
tool.py
@@ -157,6 +157,8 @@
    time_2 = get_time_as_second(time_str_2)
    if time_1 < split_time < time_2:
        time_2 = time_2 - 90 * 60
    elif time_2 < split_time < time_1:
        time_2 = time_2 + 90 * 60
    return time_1 - time_2
@@ -193,7 +195,10 @@
if __name__ == "__main__":
    print(trade_time_add_second("11:29:59", 1))
    print(trade_time_add_second("11:29:59", 5))
    print(trade_time_add_second("10:29:59", 10))
    print(trade_time_add_second("13:29:59", 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(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/current_price_process_manager.py
New file
@@ -0,0 +1,129 @@
"""
现价处理器
"""
# 获取到现价
import decimal
import logging
import client_manager
import constant
import gpcode_manager
import tool
from l2_code_operate import L2CodeOperate
from trade import trade_manager, trade_gui, l2_trade_util
from trade.trade_data_manager import CodeActualPriceProcessor
__actualPriceProcessor = CodeActualPriceProcessor()
def accept_prices(prices):
    # 获取首板代码
    first_codes = gpcode_manager.get_first_gp_codes()
    print("价格代码数量:", len(prices))
    __actualPriceProcessor.save_current_price_codes_count(len(prices))
    # 采集的代码数量不对
    if len(gpcode_manager.get_gp_list()) - len(prices) > 10:
        return
    now_str = tool.get_now_time_str()
    now_strs = now_str.split(":")
    if True:
        _code_list = []
        _delete_list = []
        for d in prices:
            code, price = d["code"], float(d["price"])
            gpcode_manager.set_price(code, price)
            # 获取收盘价
            pricePre = gpcode_manager.get_price_pre(code)
            if pricePre is not None:
                rate = round((price - pricePre) * 100 / pricePre, 2)
                if first_codes and code in first_codes:
                    rate = rate / 2
                if rate >= 0 and not trade_manager.ForbiddenBuyCodeByScoreManager.is_in(code):
                    # 暂存涨幅为正的代码
                    _code_list.append((rate, code))
                else:
                    # 暂存涨幅为负的代码
                    _delete_list.append((rate, code))
                try:
                    __actualPriceProcessor.process_rate(code, rate, now_str)
                except Exception as e:
                    logging.exception(e)
                try:
                    __actualPriceProcessor.save_current_price(code, price,
                                                              gpcode_manager.get_limit_up_price_by_preprice(
                                                                  pricePre) == tool.to_price(
                                                                  decimal.Decimal(d["price"])))
                except Exception as e:
                    logging.exception(e)
        # -------------------------------处理交易位置分配---------------------------------
        # 排序
        new_code_list = sorted(_code_list, key=lambda e: (e.__getitem__(0), e.__getitem__(1)), reverse=True)
        # 预填充下单代码
        _buy_win_codes = []
        for d in new_code_list:
            _buy_win_codes.append(d[1])
        for d in _delete_list:
            _buy_win_codes.append(d[1])
        try:
            trade_gui.THSBuyWinManagerNew.fill_codes(_buy_win_codes)
        except Exception as e:
            logging.exception(e)
            pass
        # -------------------------------处理L2监听---------------------------------
        client_ids = client_manager.getValidL2Clients()
        # 最多填充的代码数量
        max_count = len(client_ids) * constant.L2_CODE_COUNT_PER_DEVICE
        if max_count == 0:
            max_count = constant.L2_CODE_COUNT_PER_DEVICE
        _delete_list = []
        for item in new_code_list:
            if l2_trade_util.is_in_forbidden_trade_codes(item[1]) or item[0] < 0:
                _delete_list.append(item)
        for item in _delete_list:
            new_code_list.remove(item)
        # 截取前几个代码填充
        add_list = new_code_list[:max_count]
        # 后面的代码全部删除
        _delete_list.extend(new_code_list[max_count:])
        add_code_list = []
        del_code_list = []
        for d in add_list:
            add_code_list.append(d[1])
        for d in _delete_list:
            del_code_list.append(d[1])
        # 后面的代码数量
        # 先删除应该删除的代码
        for code in del_code_list:
            if gpcode_manager.is_listen_old(code):
                # 判断是否在监听里面
                L2CodeOperate.get_instance().add_operate(0, code, "现价变化")
        # 增加应该增加的代码
        for code in add_code_list:
            if not gpcode_manager.is_listen_old(code):
                L2CodeOperate.get_instance().add_operate(1, code, "现价变化")
        # 获取卡位数量
        free_count = gpcode_manager.get_free_listen_pos_count()
        if free_count < 2:
            # 空闲位置不足
            listen_codes = gpcode_manager.get_listen_codes()
            for code in listen_codes:
                if not gpcode_manager.is_in_gp_pool(code):
                    client_id, pos = gpcode_manager.get_listen_code_pos(code)
                    gpcode_manager.set_listen_code_by_pos(client_id, pos, "")
                    free_count += 1
                    if free_count > 2:
                        break
        print(add_code_list, del_code_list)
trade/deal_big_money_manager.py
@@ -62,9 +62,11 @@
    __last_progress[code] = progress
    # 计算从开始位置到成交位置
    c_index, deal_num = __get_deal_compute_progress(code)
    process_index = c_index
    for i in range(c_index + 1, progress):
        data = total_data[i]
        val = data['val']
        process_index = i
        # 是否有大单
        if not l2_data_util.is_big_money(val):
            continue
@@ -72,9 +74,10 @@
            # 是否已经取消
            cancel_data = __get_cancel_data(code, data, local_today_num_operate_map)
            if cancel_data is None:
                deal_num += val["num"]
                deal_num += val["num"] * data["re"]
                __save_traded_index(code, data["index"])
    __set_deal_compute_progress(code, progress, deal_num)
    __set_deal_compute_progress(code, process_index, deal_num)
def get_deal_big_money_num(code):
trade/first_code_score_manager.py
@@ -5,7 +5,7 @@
# bidding 是否满足竞价
# deal_big_money 成交大金额是否满足
# code_nature = (是否有涨停,是否有溢价)
# hot_block(板块中涨停票个数(包含自己),板块炸板票个数, 新板块名称 , 高位板信息)
# hot_block(板块中涨停票个数(包含自己),板块炸板票个数,板块炸板回封个数, (板块名称,出现次数), 高位板信息)
# zyltgb自由流通市值是否大于250亿
# limit_price 涨停价是否大于100块
# limit_up_time 是否10点之前涨停
@@ -24,18 +24,15 @@
                deal_big_money_rate):
    score_list = []
    if zyltgb:
        zyltgbs = [0, 10, 31, 51, 101, 150, 250, 1000000]
        zyltgb_score = [15, 25, 15, 5, -5, -55, -1000]
        for i in range(1, len(zyltgbs)):
            if zyltgbs[i - 1] <= zyltgb / 100000000 < zyltgbs[i]:
                score_list.append(zyltgb_score[i - 1])
        zyltgb_y = round(zyltgb / 100000000, 0)
        if zyltgb_y <= 80:
            score_list.append(max(int(round(0.5 * zyltgb_y - 10, 0)), -10))
        else:
            score_list.append(max(int(round(30 - 5 * ((zyltgb_y-80)//20), 0)), -10))
    else:
        score_list.append(0)
    if limit_price:
        score_list.append(-1000)
    else:
        score_list.append(0)
    score_list.append(max(int(round(-1 * limit_price + 31, 0)), -69))
    # 开盘前竞价
    if bidding:
@@ -81,7 +78,7 @@
    if k_form[6]:
        k_score.append(0)
    else:
        k_score.append(0)
        k_score.append(20)
    # 是否天量大阳
    if k_form[7] and not k_form[1]:
@@ -94,64 +91,93 @@
    nature_score = []
    # 首板涨停次数,首板溢价率,首板开板溢价率
    if code_nature is None:
        code_nature = [True, False]
    if not code_nature[0]:
        nature_score.append(5)
        code_nature = [0, 0, 0]
    if code_nature[0] <= 0:
        nature_score.append(20)
    else:
        nature_score.append(min(10 + code_nature[0], 20))
    if code_nature[1]:
        nature_score.append(min(int(round(code_nature[1] * 20 - 10)), 10))
    else:
        nature_score.append(0)
    if code_nature[1]:
        nature_score.append(20)
    if code_nature[2]:
        nature_score.append(min(int(round(code_nature[2] * 20 - 10)), 10))
    else:
        nature_score.append(0)
    score_list.append(nature_score)
    hot_block_score = []
    # 板块中只有自己涨停,且无炸板
    if hot_block[1] >= 2 and hot_block[2] == 0:
        hot_block_score.append(30)
    elif hot_block[3] and not k_form[6]:
        # 有新题材,且没有K线形态
        hot_block_score.append(30)
    elif hot_block[1] == 1 and hot_block[2] == 0:
        hot_block_score.append(20)
    elif hot_block[4] is not None and not k_form[6]:
        # 有高位板且无K线形态
        hot_block_score.append(20)
    # --------------- 板块------------------
    # 板块 - 代码平均涨幅
    __average_rate = round(hot_block["block_codes_rates_info"][0] / hot_block["block_codes_rates_info"][1], 2)
    if hot_block["target_block_info"][0] == "无板块":
        hot_block_score.append(5)
    else:
        hot_block_score.append(0)
        hot_block_score.append(min(int(round(__average_rate * 2 - 10)), 10))
    # 板块 - 涨停只数
    if hot_block["limit_up_codes_count"] <= 1:
        hot_block_score.append(1)
    else:
        hot_block_score.append(max(12 - hot_block["limit_up_codes_count"], 2))
    # 板块 - 板块涨幅
    hot_block_score.append(min(int(round(hot_block["target_block_info"][1] * 2)), 10))
    # 板块 - 第几只涨停
    if hot_block["limit_up_index"] <= 0:
        hot_block_score.append(25)
    else:
        hot_block_score.append(max(60 - hot_block["limit_up_index"] * 5, 10))
    # 板块 - 高位板
    high_score = 0
    for high_info in hot_block["high_block_infos"]:
        c_count = int(high_info[1][-2:-1])
        high_score += min(2 * c_count - 2, 10)
    hot_block_score.append(high_score)
    # 板块 - 板块历史出现次数
    if hot_block["target_block_info"][2] <= 1:
        hot_block_score.append(10)
    else:
        hot_block_score.append(max(-3 * hot_block["target_block_info"][2] + 20, -10))
    score_list.append(hot_block_score)
    # --------------- 板块结束-----------------
    # 量
    volume_score = [0, 40, 50, 60, 50, 40, 20, 0, -25]
    volume_rates = [0, 0.349, 0.499, 0.649, 0.799, 0.949, 1.099, 1.249, 1.399]
    volume_add = False
    for i in range(1, len(volume_rates)):
        if volume_rates[i - 1] <= volume_rate < volume_rates[i]:
            score_list.append(volume_score[i - 1])
            volume_add = True
            break
    if not volume_add:
        score_list.append(volume_score[-1])
    if volume_rate <= 0.5:
        score_list.append(int(round(100 * volume_rate)))
    elif volume_rate < 0.6:
        score_list.append(50)
    elif volume_rate < 0.7:
        score_list.append(55)
    elif volume_rate <= 1.0:
        score_list.append(60)
    else:
        score_list.append(max(int(round(-100 * volume_rate + 160, 0)), -20))
    # 初始化为当前时间
    limit_up_time_m = tool.trade_time_sub(tool.get_now_time_str(), "09:00:00") // 60
    if limit_up_time:
        times = ["10:00:00", "11:30:00", "14:00:00", "15:00:00"]
        time_scores = [5, 4, 3, 2]
        for i in range(0, len(times)):
            if int(times[i].replace(":", "")) >= int(limit_up_time.replace(":", "")):
                score_list.append(time_scores[i])
                break
        limit_up_time_m = tool.trade_time_sub(limit_up_time, "09:00:00") // 60
    if limit_up_time_m < 240:
        # 14:30之前适用
        score_list.append(min(int(0 - round(limit_up_time_m / 15) + 12), 10))
    elif limit_up_time_m <= 270:
        # 15:00之前加
        score_list.append(100)
    else:
        score_list.append(0)
    # 大单成交
    deal_big_money_rates = [0, 0.00001, 0.5, 1, 1.2, 1.5, 10000]
    deal_big_money_scores = [0, -20, -10, 20, 30, 40]
    for i in range(1, len(deal_big_money_rates)):
        if deal_big_money_rate < deal_big_money_rates[i]:
            score_list.append(deal_big_money_scores[i - 1])
    if deal_big_money_rate < 1:
        score_list.append(0)
    else:
        d_score = int(round(10 * deal_big_money_rate, 0))
        d_score = min(d_score, 60)
        score_list.append(d_score)
    score = 0
    for s in score_list:
@@ -163,7 +189,7 @@
    return score, score_list
def get_score(code, volume_rate, limit_up_time, with_source_data=False):
def get_score(code, volume_rate, limit_up_time, with_source_data=False, estimate_deal_big_money_num=0):
    source_datas = []
    # 获取自由流通股本
@@ -208,10 +234,28 @@
    hot_block = hot_block_data_process.get_info(code)
    if hot_block is None:
        hot_block = ('无板块', 1, 0, None, None)
    else:
        # 加上自己
        hot_block = (hot_block[0], hot_block[1] + 1, hot_block[2], hot_block[3], hot_block[4])
        hot_block = {
            # 目标板块信息(板块名称,板块涨幅,历史板块出现次数)
            "target_block_info": ("无板块", 0, 0),
            # 涨停顺序
            "limit_up_index": 0,
            # 涨停代码数量
            "limit_up_codes_count": 0,
            # 板块代码涨幅信息
            "block_codes_rates_info": (0, 0),
            # 炸板代码数量
            "break_size": 0,
            # 炸板回封数量
            "re_limit_up_size": 0,
            # 高位版信息
            "high_block_infos": [],
        }
    # 将代码本身的信息包含进去
    hot_block["limit_up_codes_count"] = hot_block["limit_up_codes_count"] + 1
    pre_close_price = gpcode_manager.get_price_pre(code)
    hot_block["block_codes_rates_info"] = (
        hot_block["block_codes_rates_info"][0] + round((limit_price - pre_close_price) * 100 / pre_close_price, 2),
        hot_block["block_codes_rates_info"][1] + 1)
    source_datas.append(hot_block)
@@ -221,6 +265,8 @@
    # 获取成交大单
    deal_big_num = deal_big_money_manager.get_deal_big_money_num(code)
    if estimate_deal_big_money_num > 0:
        deal_big_num = estimate_deal_big_money_num
    m = l2_trade_factor.L2TradeFactorUtil.get_base_safe_val(zyltgb)
    source_datas.append((deal_big_num * limit_price * 100, m))
    deal_big_num_rate = (deal_big_num * limit_price * 100) / m
@@ -228,7 +274,7 @@
    for i in range(0, len(k_form)):
        k_form_1.append(k_form[i][0])
    result = __get_score(zyltgb, limit_price > 100, bidding, k_form_1, code_nature, hot_block,
    result = __get_score(zyltgb, limit_price, bidding, k_form_1, code_nature, hot_block,
                         volume_rate, limit_up_time, deal_big_num_rate)
    if with_source_data:
        return result, source_datas
@@ -236,6 +282,10 @@
if __name__ == "__main__":
    global_data_loader.load_zyltgb()
    score = get_score("603829", 1.2, "15:00:01", True)
    print(score)
    limit_price = 35
    prices = [0, 5, 10, 20, 30, 40, 50, 10000]
    price_scores = [20, 15, 10, 0, -10, -20, -1000]
    for i in range(1, len(prices)):
        if prices[i] > limit_price:
            print(price_scores[i - 1])
            break
trade/l2_trade_factor.py
@@ -8,17 +8,79 @@
import constant
import global_data_loader
import global_util
import gpcode_manager
import limit_up_time_manager
# 下单参数
import tool
from l2 import code_price_manager
class L2PlaceOrderParamsManager:
    # 获取买入等级描述
    def get_buy_rank_desc(self):
        continue_count = self.get_begin_continue_buy_count()
        time_range = self.get_time_range()
        desc = ""
        if self.buy_rank == 0:
            desc = f"买入信号({continue_count})"
        elif self.buy_rank == 1:
            desc = f"买入信号({continue_count})+M值≥1000万"
        elif self.buy_rank == 2:
            desc = f"买入信号({continue_count})+M值≥1000万+至少含1笔大单"
        elif self.buy_rank == 3:
            desc = f"买入信号({continue_count})+M值≥1000万+至少含2笔大单"
        else:
            desc = "常规买入"
        desc += f"+囊括时间{time_range}s"
        return desc
    # 获取买入等级
    # 0:买入信号
    # 1:买入信号+M1000万
    # 2:买入信号+M1000万+1笔大单
    # 3:买入信号+M1000+2笔大单
    # 100:执行之前固有方案
    def get_buy_rank(self):
        # 判断有没有炸开
        if code_price_manager.Buy1PriceManager.is_can_buy(self.code):
            # 回封
            if self.score_index == 0:
                return 0
            elif self.score_index == 1:
                return 1
            elif self.score_index == 2:
                return 2
            else:
                return 100
        else:
            # 首封
            if tool.trade_time_sub(self.now_time, "10:30:00") < 0 or tool.trade_time_sub(self.now_time, "14:00:00") > 0:
                if self.score_index == 0:
                    return 1
                elif self.score_index == 1:
                    return 2
                elif self.score_index == 2:
                    return 3
                else:
                    return 100
            else:
                if self.score_index == 0:
                    return 2
                elif self.score_index == 1:
                    return 3
                elif self.score_index == 2:
                    return 100
                else:
                    return 100
    # 得分
    def __init__(self, code, is_first_code, volume_rate, volume_rate_index, score):
    def __init__(self, code, is_first_code, volume_rate, volume_rate_index, score, now_time=tool.get_now_time_str()):
        self.code = code
        self.is_first_code = is_first_code
        score_ranks = [200, 190, 180, 100]
        score_ranks = [constant.BUY_SCORE_RANK_3, constant.BUY_SCORE_RANK_2, constant.BUY_SCORE_RANK_1,
                       constant.BUY_SCORE_RANK_0]
        self.score = score[0][0]
        self.score_info = score
        # 为分数设置等级
@@ -28,8 +90,28 @@
                score_index = i
                break
        self.score_index = score_index
        # 只要加入想买单的,全部执行主动买入一星方案
        if gpcode_manager.WantBuyCodesManager.is_in(code) and self.score_index >= 3:
            self.score_index = 2
        self.volume_rate = volume_rate
        self.volume_rate_index = volume_rate_index
        self.now_time = now_time
        self.buy_rank = self.get_buy_rank()
    # 设置分数
    def set_score(self, score):
        score_ranks = [constant.BUY_SCORE_RANK_3, constant.BUY_SCORE_RANK_2, constant.BUY_SCORE_RANK_1,
                       constant.BUY_SCORE_RANK_0]
        self.score = score[0][0]
        self.score_info = score
        # 为分数设置等级
        score_index = -1
        for i in range(0, len(score_ranks)):
            if self.score >= score_ranks[i]:
                score_index = i
                break
        self.score_index = score_index
    # 获取信号连续买笔数
@@ -43,6 +125,8 @@
    # 获取时间计算范围,返回s
    def get_time_range(self):
        ts = [pow(3, 1), pow(3, 1), pow(3, 1), pow(3, 2), pow(3, 2), pow(3, 3), pow(3, 3), pow(3, 3)]
        if -1 < self.score_index < 3:
            return ts[0]
        volume_rate_index = self.volume_rate_index
        if self.volume_rate_index >= len(ts):
            volume_rate_index = -1
@@ -51,14 +135,12 @@
    # 获取需要的大单个数
    def get_big_num_count(self):
        if self.is_first_code:
            if self.score_index == 0:
            if self.buy_rank < 2:
                return 0
            elif self.score_index == 1:
                return 0
            elif self.score_index == 2:
            elif self.buy_rank == 2:
                return 1
            elif self.score_index < 0:
                return 65535
            elif self.buy_rank == 3:
                return 2
        counts = [3, 1, 1, 1, 0, 0, 0, 0]
        volume_rate_index = self.volume_rate_index
        if self.volume_rate_index >= len(counts):
@@ -75,10 +157,8 @@
    def get_safe_count(self):
        if self.is_first_code:
            if 3 > self.score_index > -1:
            if self.buy_rank < 4:
                return 2
            elif self.score_index < 0:
                return 65535
        base_count, min_count, max_count = L2TradeFactorUtil.get_safe_buy_count(self.code, True)
        rate = self.get_safe_count_rate()
        count = int(round(base_count * (1 + rate)))
@@ -87,7 +167,7 @@
    # 获取m值影响比例
    @classmethod
    def get_m_val_rate(cls, volume_rate_index):
        rates = [0.0, 0.0, 0.0, -0.3, -0.4, -0.5, -0.6, -0.7]
        rates = [0.0, -0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7]
        if volume_rate_index >= len(rates):
            volume_rate_index = -1
        return rates[volume_rate_index]
@@ -95,14 +175,10 @@
    # 获取m值
    def get_m_val(self):
        if self.is_first_code:
            if self.score_index == 0:
            if self.buy_rank == 0:
                return 0, ""
            elif self.score_index == 1:
            elif self.buy_rank < 4:
                return 1000 * 10000, ""
            elif self.score_index == 2:
                return 1000 * 10000, ""
            elif self.score_index < 0:
                return 65535 * 10000, ""
        # 获取固定m值
        zyltgb = global_util.zyltgb_map.get(self.code)
        if zyltgb is None:
@@ -128,7 +204,8 @@
    # 获取买时间范围(距离执行位),返回s
    @staticmethod
    def get_buy_time_range(volume_rate_index):
        seconds = [pow(2, 1), pow(2, 2), pow(2, 3), pow(2, 4), pow(2, 4), pow(2, 5), pow(2, 6), pow(2, 6)]
        # rates = [0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6]
        seconds = [pow(2, 1), pow(2, 2), pow(2, 3), pow(2, 4), pow(2, 5), pow(2, 5), pow(2, 4), pow(2, 4)]
        if volume_rate_index >= len(seconds):
            volume_rate_index = -1
        return seconds[volume_rate_index]
@@ -388,7 +465,7 @@
            MAX_VAL = 13
        if not gb:
            # 默认8笔
            return MIN_VAL,MIN_VAL, MAX_VAL
            return MIN_VAL, MIN_VAL, MAX_VAL
        count = gb // 100000000
        if True:
            if count < 8:
trade/trade_gui.py
@@ -4,19 +4,22 @@
import array
import logging
import re
import threading
import time
import random
import numpy
import win32gui
import win32con
import constant
from ocr import ocr_util
from trade import l2_trade_util
from db import redis_manager
from log import *
from tool import async_call
from utils import win32_util
from utils import win32_util, capture_util
class THSGuiTrade(object):
@@ -268,10 +271,10 @@
            #     raise Exception(error)
            # TODO 暂时不验证涨停价
            if not constant.TEST:
                if abs(float(limit_up_price_now) - float(limit_up_price)) >= 0.01:
                    error = "涨停价验证出错 {}-{}".format(limit_up_price, limit_up_price_now)
                    raise Exception(error)
            # if not constant.TEST:
            #     if abs(float(limit_up_price_now) - float(limit_up_price)) >= 0.01:
            #         error = "涨停价验证出错 {}-{}".format(limit_up_price, limit_up_price_now)
            #         raise Exception(error)
            # 开始交易,买入按钮ID:0x000003EE
            # buy_hwnd = win32gui.GetDlgItem(win, 0x000003EE)
@@ -460,8 +463,6 @@
                    self.buy_cancel_locks[w] = threading.RLock()
class THSGuiUtil:
    @classmethod
    def getText(cls, hwnd):
@@ -648,7 +649,9 @@
            if win in win_set:
                win_set.remove(win)
        if len(win_set) > 0:
            return win_set.pop()
            win_list = list(win_set)
            random.shuffle(win_list)
            return win_list[0]
        # 没有剩余的窗口,新增加窗口
        raise Exception("没有剩余窗口")
@@ -678,9 +681,14 @@
            THSGuiUtil.set_buy_window_code(cls.get_trade_win(win), code)
            time.sleep(0.5)
            code_name_win = cls.__get_code_name(win)
            if code_name == code_name_win:
                is_success = True
                break
            if code_name == code_name_win or code_name_win.find(code_name) > -1:
                if cls.__is_buy_limit_up_price(win):
                    is_success = True
                    break
                else:
                    cls.__del_code_win(code)
                    THSGuiUtil.set_buy_window_code(cls.get_trade_win(win), "")
                    raise Exception("不是买涨停价")
        if is_success:
            logger_buy_win_distibute.info(f"新分配窗口成功:{code}-{win}")
        else:
@@ -733,6 +741,18 @@
            name = name.replace(" ", "")
        return tool.strQ2B(name)
    # 是否是涨停价
    @classmethod
    def __is_buy_limit_up_price(cls, win):
        trade_win = cls.get_trade_win(win)
        if trade_win is None:
            return None
        price_win = win32gui.GetDlgItem(trade_win, 0x00000409)
        ocr_result = ocr_util.OcrUtil.ocr_with_key(capture_util.window_capture(price_win), "涨停价|张停价")
        if ocr_result:
            return True
        return False
    @classmethod
    def fill_codes(cls, codes):
        name_codes = gpcode_manager.get_name_codes()
@@ -754,7 +774,7 @@
                new_delete_codes.append(code)
        cancel_wins = THSGuiTrade.getCancelBuyWins()
        add_codes_num = len(cancel_wins)*10
        add_codes_num = len(cancel_wins) * 10
        add_codes = new_codes[0:add_codes_num]
        del_codes = new_codes[add_codes_num:]
        del_codes.extend(new_delete_codes)
@@ -780,6 +800,11 @@
                print("分配的窗口:", win, THSGuiUtil.is_win_exist(win))
            except Exception as e:
                logging.exception(e)
# 根据涨幅高低分配交易窗口
def re_distribute_buy_win(codes):
    THSBuyWinManagerNew.fill_codes(codes)
class GUITest:
@@ -809,10 +834,10 @@
if __name__ == '__main__':
    pass
    # try:
    #     THSGuiTrade().cancel_buy_again("000637")
    # except Exception as e:
    #     print(e)
    print(THSGuiTrade().cancel_buy("000582"))
    print(ocr_util.OcrUtil.ocr_with_key(capture_util.window_capture(0x000314EA), "涨停价|张停价"))
    # THSGuiTrade().buy("600613", 10.29)
trade/trade_manager.py
@@ -9,7 +9,7 @@
from db import mysql_data, redis_manager
from trade import trade_data_manager, l2_trade_util
from trade.trade_gui import THSBuyWinManagerNew, THSGuiTrade
import trade.trade_gui
import time as t
from l2 import l2_data_manager, l2_data_log
@@ -30,7 +30,7 @@
# 买成功
TRADE_STATE_BUY_SUCCESS = 12
guiTrade = THSGuiTrade()
guiTrade = trade.trade_gui.THSGuiTrade()
latest_trade_delegate_data = []
@@ -65,6 +65,33 @@
            return True
        else:
            return False
# 根据分数禁止买的票管理
class ForbiddenBuyCodeByScoreManager:
    __redisManager = redis_manager.RedisManager(2)
    __key = "forbidden_codes_by_score"
    @classmethod
    def __get_redis(cls):
        return cls.__redisManager.getRedis()
    @classmethod
    def add_code(cls, code):
        cls.__get_redis().sadd(cls.__key,code)
    @classmethod
    def remove_code(cls, code):
        cls.__get_redis().srem(cls.__key, code)
    @classmethod
    def is_in(cls, code):
        return cls.__get_redis().sismember(cls.__key, code)
    @classmethod
    def clear(cls):
        cls.__get_redis().delete(cls.__key)
# 获取交易状态
@@ -383,7 +410,7 @@
                l2_data_manager.TradePointManager.delete_buy_cancel_point(code)
                l2_data_manager.TradePointManager.delete_buy_point(code)
                # 移除交易窗口分配
                THSBuyWinManagerNew.cancel_distribute_win_for_code(code)
                trade.trade_gui.THSBuyWinManagerNew.cancel_distribute_win_for_code(code)
            # 交易成功时间过去3s之后,且当前委托列表里面还有该代码数据就再次执行撤单
            if tool.trade_time_sub(tool.get_now_time_str(), _time) > 3:
                # 获取到当前是否委托
@@ -450,4 +477,4 @@
if __name__ == "__main__":
    cancel_buy_again("000637")
    pass