Administrator
2025-06-10 efe62c0c92bee36da5179f34bb73e8ee4db6f814
cancel_strategy/s_l_h_cancel_strategy.py
@@ -1,3 +1,4 @@
import copy
import json
import time
@@ -12,10 +13,10 @@
from l2.l2_transaction_data_manager import HuaXinBuyOrderManager, HuaXinSellOrderStatisticManager, BigOrderDealManager
from log_module import async_log_util
from third_data import code_plate_key_manager
from trade.buy_radical import radical_buy_data_manager
from utils import tool
from l2.transaction_progress import TradeBuyQueue
from trade import l2_trade_factor, trade_record_log_util
from trade import l2_trade_factor, trade_record_log_util, trade_constant
from l2 import l2_log, l2_data_source_util
from l2.l2_data_util import L2DataUtil, local_today_datas, local_today_canceled_buyno_map, local_today_buyno_map
from log_module.log import logger_l2_s_cancel, logger_debug, logger_l2_l_cancel, logger_l2_h_cancel
@@ -169,7 +170,7 @@
        @param code:
        @return:(大单阈值, 800w内大单阈值)
        """
        max60, yesterday = code_volumn_manager.get_histry_volumn(code)
        max60, yesterday = code_volumn_manager.CodeVolumeManager().get_histry_volumn(code)
        if max60:
            num = max60[0]
            limit_up_price = gpcode_manager.get_limit_up_price(code)
@@ -220,8 +221,10 @@
            cancel_result = self.__need_cancel_for_slow_sell(code, total_datas)
            if cancel_result[0]:
                return True, f"S慢砸:{cancel_result[1]}"
        if total_deal_money >= 100 * 10000:
        # 卖金额>=均大单才触发重新囊括
        THRESHOLD_MONEY, is_temp_threshold_money = radical_buy_data_manager.BeforeSubDealBigOrderManager().get_big_order_threshold_info(
            code)
        if total_deal_money >= THRESHOLD_MONEY:
            l2_log.s_cancel_debug(code, "准备更新L后囊括")
            start_order_no = big_sell_order_info[1][-1][4][1]
            latest_deal_time_ms = l2_huaxin_util.convert_time(big_sell_order_info[1][-1][4][0], with_ms=True)
@@ -466,7 +469,7 @@
                    # 15分钟内真实成交位距离真实下单位,金额≤800万 ,大单阈值变为200w
                    threash_money_w = threash_money_danger_w
        except Exception as e:
            l2_log.s_cancel_debug(code, f"S撤激进下单计算大单卖阈值出错:{str(e)}")
            l2_log.s_cancel_debug(code, f"S撤积极下单计算大单卖阈值出错:{str(e)}")
        total_fast_money = int(total_fast_num * 100 * float(limit_up_price))
        if total_fast_money == 0:
            # 防止分母为0
@@ -564,9 +567,28 @@
    # 获取撤单比例,返回(撤单比例,是否必买)
    @classmethod
    def get_cancel_rate(cls, code, buy_exec_time, is_up=False, is_l_down_recomputed=False):
    def get_cancel_rate(cls, code, is_up=False, is_l_down_recomputed=False, buy_mode=None):
        try:
            must_buy = cls.__MustBuyCodesManager.is_in_cache(code)
            if buy_mode == OrderBeginPosInfo.MODE_RADICAL:
                if must_buy:
                    # 扫入加红
                    return constant.L_CANCEL_RATE_WITH_MUST_BUY_FOR_REDICAL_BUY, True
                else:
                    # 根据成交额的大单成交占比来计算撤单比例
                    big_money_rate = radical_buy_data_manager.TotalDealBigOrderInfoManager.get_big_order_rate(code)
                    if big_money_rate is not None:
                        threshold_rate = min(big_money_rate * 3, 0.95)
                        return threshold_rate, False
                    else:
                        deal_big_order_info = radical_buy_data_manager.get_total_deal_big_order_info(code,
                                                                                                     gpcode_manager.get_limit_up_price_as_num(
                                                                                                         code))
                        deal_rate = round(deal_big_order_info[1] / deal_big_order_info[2], 2)
                        threshold_rate = 0.5 * deal_rate + 0.35
                        threshold_rate = max(threshold_rate, 0.375)
                        threshold_rate = min(threshold_rate, 0.95)
                        return threshold_rate, False
            if must_buy:
                if is_up:
                    return constant.L_CANCEL_RATE_UP_WITH_MUST_BUY, True
@@ -883,7 +905,7 @@
                # 计算的上截至位距离下截至位纯买额要小于2.5倍m值
                # thresh_hold_money = l2_trade_factor.L2PlaceOrderParamsManager.get_base_m_val(code)
                # thresh_hold_money = int(thresh_hold_money * 2.5)
                min_num = int(5000 / (float(gpcode_manager.get_limit_up_price(code))))
                min_num = int(5000 / gpcode_manager.get_limit_up_price_as_num(code))
                # 统计净涨停买的数量
                not_cancel_indexes_with_num = []
                re_start_index = start_index
@@ -924,7 +946,7 @@
                        if temp_count >= 10:
                            # 获取中位数
                            min_num = not_cancel_indexes_with_num[temp_count // 2][1]
                MIN_MONEYS = [300, 200, 100, 50]
                MIN_MONEYS = [300, 200, 100]
                watch_indexes = set()
                for min_money in MIN_MONEYS:
                    for i in range(end_index, re_start_index - 1, -1):
@@ -963,12 +985,17 @@
                        break
                if watch_indexes:
                    ##判断监听的数据中是否有大单##
                    # 之前的大单为100w,现在改为正常大单
                    has_big_num = False
                    BIG_ORDER_NUM_THRESHOLD = l2_data_util.get_big_money_val(
                        gpcode_manager.get_limit_up_price_as_num(code), tool.is_ge_code(code))
                    BIG_ORDER_NUM_THRESHOLD = int(
                        round(BIG_ORDER_NUM_THRESHOLD / (gpcode_manager.get_limit_up_price_as_num(code) * 100)))
                    for i in watch_indexes:
                        # 是否有大单
                        data = total_datas[i]
                        val = data['val']
                        if float(val['price']) * val['num'] > 100 * 100:
                        if val['num'] > BIG_ORDER_NUM_THRESHOLD:
                            has_big_num = True
                            break
                    if not has_big_num:
@@ -980,7 +1007,7 @@
                            if not L2DataUtil.is_limit_up_price_buy(val):
                                continue
                            # 小金额过滤
                            if float(val['price']) * val['num'] < 100 * 100:
                            if val['num'] < BIG_ORDER_NUM_THRESHOLD:
                                continue
                            cancel_data = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_canceled_data_v2(code,
                                                                                                                  i,
@@ -996,6 +1023,28 @@
                                                                                           cancel_data['val'])) <= 0:
                                watch_indexes.add(i)
                                break
                    # 计算真实下单位置到成交进度位的最大未撤大单前2
                    big_order_list = []
                    for i in range(start_index, end_index):
                        data = total_datas[i]
                        val = data['val']
                        # 涨停买,且未撤单
                        if not L2DataUtil.is_limit_up_price_buy(val):
                            continue
                        # 小金额过滤
                        if val['num'] < BIG_ORDER_NUM_THRESHOLD:
                            continue
                        cancel_data = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_canceled_data_v2(code,
                                                                                                              i,
                                                                                                              total_datas,
                                                                                                              local_today_canceled_buyno_map.get(
                                                                                                                  code))
                        if not cancel_data:
                            big_order_list.append((i, val['num']))
                    if big_order_list:
                        big_order_list.sort(key=lambda x: x[1], reverse=True)
                        watch_indexes |= set([x[0] for x in big_order_list[:2]])
                    # 获取真实下单位后面10笔大单
                    watch_indexes_after = self.__compute_l_down_watch_index_after_real_place_order_index(code)
                    if watch_indexes_after:
@@ -1027,10 +1076,10 @@
            if index > real_place_order_index:
                # L后后段已经囊括
                return False
        # 下单位置之后数10笔卖单
        # 下单位置之后数10笔买单
        watch_indexes = set()
        total_datas = local_today_datas.get(code)
        MIN_NUM = int(5000 / (float(gpcode_manager.get_limit_up_price(code))))
        MIN_NUM = int(5000 / gpcode_manager.get_limit_up_price_as_num(code))
        MAX_COUNT = 10
        for i in range(real_place_order_index + 1, end_index):
            data = total_datas[i]
@@ -1071,7 +1120,7 @@
        is_ge_code = tool.is_ge_code(code)
        try:
            # 真实下单位置后面的数据就只看大单
            MIN_NUM = int(5000 / (float(gpcode_manager.get_limit_up_price(code))))
            MIN_NUM = int(5000 / gpcode_manager.get_limit_up_price_as_num(code))
            real_place_order_info = self.__real_place_order_index_dict.get(code)
            if real_place_order_info and not real_place_order_info[1]:
                # 从真实下单位往后找
@@ -1337,7 +1386,7 @@
        is_ge_code = tool.is_ge_code(code)
        if real_place_order_info and real_place_order_info[0] > index:
            total_datas = local_today_datas.get(code)
            min_num = int(5000 / (float(gpcode_manager.get_limit_up_price(code))))
            min_num = int(5000 / gpcode_manager.get_limit_up_price_as_num(code))
            for j in range(real_place_order_info[0] - 1, index, -1):
                data = total_datas[j]
                val = data['val']
@@ -1430,8 +1479,7 @@
        # 计算监听的总条数
        total_num = 0
        max_num = 0
        thresh_hold_rate, must_buy = LCancelRateManager.get_cancel_rate(code,
                                                                        total_data[buy_exec_index]["val"]["time"])
        thresh_hold_rate, must_buy = LCancelRateManager.get_cancel_rate(code)
        for wi in watch_indexes:
            if str(wi) in after_place_order_index_dict:
@@ -1470,12 +1518,16 @@
            canceled_num = 0
            # 记录撤单索引
            canceled_indexes = []
            deal_order_nos = HuaXinBuyOrderManager().get_deal_buy_order_nos(code)
            if deal_order_nos is None:
                deal_order_nos = set()
            trade_index, is_default = TradeBuyQueue().get_traded_index(code)
            if is_default:
                trade_index = None
            canceled_buyno_map = local_today_canceled_buyno_map.get(code)
            for wi in watch_indexes:
                cancel_data = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_canceled_data_v2(code,
                                                                                                      wi,
                                                                                                      total_data,
                                                                                                      local_today_canceled_buyno_map.get(
                                                                                                          code))
                cancel_data = L2DataComputeUtil.is_canceled(code, wi, total_data, canceled_buyno_map, trade_index, deal_order_nos)
                if cancel_data:
                    if str(wi) in after_place_order_index_dict:
                        # 真实下单位置之后的按照权重比例来计算
@@ -1486,7 +1538,6 @@
                                10 - after_place_order_index_by_dict[str(wi)]) // 10
                    else:
                        canceled_num += total_data[wi]["val"]["num"]
                    canceled_indexes.append(cancel_data["index"])
                # if wi == watch_indexes_list[-1] and left_count == 0:
                #     # 离下单位置最近的一个撤单,必须触发撤单
@@ -1498,7 +1549,10 @@
            # 除开最大单的影响权重
            if not must_buy:
                temp_thresh_hold_rate = round((total_num - max_num) * 0.9 / total_num, 2)
                thresh_hold_rate = min(thresh_hold_rate, temp_thresh_hold_rate)
                if thresh_hold_rate > temp_thresh_hold_rate:
                    # 目标撤单比例大于大单撤单比例就取比例均值
                    thresh_hold_rate = round((thresh_hold_rate + temp_thresh_hold_rate) / 2, 2)
            l2_log.l_cancel_debug(code,
                                  f"L后计算范围:{start_index}-{end_index},已撤单比例:{rate}/{thresh_hold_rate}, 下单位之后的索引:{after_place_order_index_dict}")
            if rate >= thresh_hold_rate:
@@ -1566,9 +1620,7 @@
                    else:
                        canceled_count_weight += WATCH_INDEX_WEIGHTS[-1]
            rate = round(canceled_count_weight / total_count_weight, 3)
            thresh_cancel_rate, must_buy = LCancelRateManager.get_cancel_rate(code,
                                                                              total_data[buy_exec_index]["val"]["time"],
                                                                              is_up=True)
            thresh_cancel_rate, must_buy = LCancelRateManager.get_cancel_rate(code, is_up=True)
            l2_log.l_cancel_debug(code, f"计算范围:{start_index}-{end_index},L前已撤单比例:{rate}/{thresh_cancel_rate}")
            if rate >= thresh_cancel_rate:
                # 计算成交进度位置到当前下单位置的纯买额
@@ -1581,7 +1633,7 @@
                    thresh_hold_money = l2_trade_factor.L2PlaceOrderParamsManager.get_base_m_val(code)
                    thresh_hold_money = thresh_hold_money * 3
                    # 阈值为2倍m值
                    thresh_hold_num = thresh_hold_money // (float(gpcode_manager.get_limit_up_price(code)) * 100)
                    thresh_hold_num = thresh_hold_money // (gpcode_manager.get_limit_up_price_as_num(code) * 100)
                    for i in range(trade_progress_index + 1, real_place_order_index_info[0]):
                        data = total_data[i]
                        val = data['val']
@@ -1598,14 +1650,96 @@
                            if total_num > thresh_hold_num:
                                # 成交位到下单位还有足够的单没撤
                                l2_log.l_cancel_debug(code,
                                                      f"L上撤阻断: 成交位-{trade_progress_index} 真实下单位-{real_place_order_index_info[0]} 阈值-{thresh_hold_money}")
                                                      f"L前撤阻断: 成交位-{trade_progress_index} 真实下单位-{real_place_order_index_info[0]} 阈值-{thresh_hold_money}")
                                return False, None
                canceled_indexes.sort()
                l2_log.l_cancel_debug(code, f"L上撤单,撤单位置:{canceled_indexes[-1]}")
                l2_log.l_cancel_debug(code, f"L前撤单,撤单位置:{canceled_indexes[-1]}")
                return True, total_data[canceled_indexes[-1]]
        return False, None
    # L后重新囊括的时间
    __recompute_l_down_time_dict = {}
    def set_big_sell_order_info(self, code, big_sell_order_info):
        """
        设置大卖单信息
        @param code:
        @param big_sell_order_info:
        @return:
        """
        if not big_sell_order_info or not big_sell_order_info[0] or not big_sell_order_info[1]:
            return False, ""
        total_datas = local_today_datas.get(code)
        # 查询是否是真的真实下单位置
        trade_index, is_default = TradeBuyQueue().get_traded_index(code)
        if trade_index is None:
            trade_index = 0
        real_order_index_info = self.get_real_place_order_index_info(code)
        if real_order_index_info is None or real_order_index_info[1]:
            return False, "没找到真实下单位"
        real_order_index = real_order_index_info[0]
        total_deal_money = sum([x[1] * x[2] for x in big_sell_order_info[1]])
        start_order_no = big_sell_order_info[1][0][3][1]
        # 防止分母位0
        total_num = 1
        # 获取正在成交的数据
        dealing_info = HuaXinBuyOrderManager.get_dealing_order_info(code)
        for i in range(trade_index, real_order_index):
            data = total_datas[i]
            val = data['val']
            if not L2DataUtil.is_limit_up_price_buy(val):
                continue
            if int(val['orderNo']) < start_order_no:
                continue
            if i == trade_index and dealing_info and str(total_datas[trade_index]["val"]["orderNo"]) == str(
                    dealing_info[0]):
                # 减去当前正在成交的数据中已经成交了的数据
                total_num -= dealing_info[1] // 100
            left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(code, i,
                                                                                                     total_datas,
                                                                                                     local_today_canceled_buyno_map.get(
                                                                                                         code))
            if left_count > 0:
                total_num += val["num"]
        # 卖金额>=均大单才触发重新囊括
        THRESHOLD_MONEY = radical_buy_data_manager.BeforeSubDealBigOrderManager().get_big_sell_order_threshold(code)
        if total_deal_money >= THRESHOLD_MONEY:
            l2_log.l_cancel_debug(code, "准备更新L后囊括(大卖单)")
            start_order_no = big_sell_order_info[1][-1][4][1]
            latest_deal_time_ms = l2_huaxin_util.convert_time(big_sell_order_info[1][-1][4][0], with_ms=True)
            real_trade_index = None
            for i in range(trade_index, real_order_index):
                data = total_datas[i]
                val = data['val']
                if not L2DataUtil.is_limit_up_price_buy(val):
                    continue
                if int(val['orderNo']) < start_order_no:
                    continue
                real_trade_index = i
                break
            if real_trade_index is None:
                l2_log.l_cancel_debug(code, f"没找到真实的成交进度(大卖单):start_order_no-{start_order_no} 卖单-{big_sell_order_info}")
                return False, ""
            # 间隔1S以上才能重新囊括
            if code in self.__recompute_l_down_time_dict and tool.trade_time_sub_with_ms(latest_deal_time_ms,
                                                                                         self.__recompute_l_down_time_dict[
                                                                                             code]) < 1000:
                l2_log.s_cancel_debug(code,
                                      f"更新L后囊括(大卖单):更新间隔在1s内,{latest_deal_time_ms}-{self.__recompute_l_down_time_dict[code]}")
                return False, ""
            self.__recompute_l_down_time_dict[code] = latest_deal_time_ms
            # 重新囊括L后
            # 撤单时间比早成交时间大就需要计算在里面
            self.re_compute_l_down_watch_indexes(code, big_sell_info=(
                real_trade_index, latest_deal_time_ms))
            l2_log.l_cancel_debug(code, f"更新L后囊括完成(大卖单):{(real_trade_index, latest_deal_time_ms)}")
        else:
            l2_log.l_cancel_debug(code, f"大卖单金额不足({THRESHOLD_MONEY})")
        return False, ""
    # L后是否还有可能撤单
    def __is_l_down_can_cancel(self, code, buy_exec_index):
@@ -1639,28 +1773,29 @@
            total_nums += val["num"]
            if left_count > 0 and index < trade_index:
                total_deal_nums += val["num"]
        thresh_hold_rate, must_buy = LCancelRateManager.get_cancel_rate(code,
                                                                        total_datas[buy_exec_index]["val"]["time"])
        thresh_hold_rate, must_buy = LCancelRateManager.get_cancel_rate(code)
        if total_deal_nums / total_nums > 1 - thresh_hold_rate - 0.05:
            return False
        return True
    def need_cancel(self, code, buy_exec_index, start_index, end_index, total_data, is_first_code):
        if buy_exec_index is None:
            return False, None, "尚未找到下单位置"
            return False, None, "尚未找到下单位置", None
        # 守护S撤以外的数据
        if int(tool.get_now_time_str().replace(":", "")) > int("145700") and not constant.TEST:
            return False, None, ""
            return False, None, "", None
        try:
            LCancelOutOfDateWatchIndexesManager().process(code, start_index, end_index)
        except Exception as e:
            l2_log.l_cancel_debug("L后稳定更新出错:{}",str(e))
            l2_log.l_cancel_debug("L后稳定更新出错:{}", str(e))
        # 下单位临近撤
        can_cancel, cancel_data = False, None
        can_cancel, cancel_data, cancel_type = False, None, None
        try:
            can_cancel, cancel_data = self.__compute_need_cancel(code, buy_exec_index, start_index, end_index,
                                                                 total_data,
                                                                 is_first_code)
            if can_cancel:
                cancel_type = trade_constant.CANCEL_TYPE_L_DOWN
        except Exception as e:
            logger_l2_l_cancel.exception(e)
            raise e
@@ -1672,6 +1807,8 @@
                                                                                            start_index, end_index,
                                                                                            total_data,
                                                                                            is_first_code)
                if can_cancel:
                    cancel_type = trade_constant.CANCEL_TYPE_L_UP
                extra_msg = "L前"
            except Exception as e:
                logger_l2_l_cancel.exception(e)
@@ -1691,7 +1828,7 @@
        except Exception as e:
            l2_log.l_cancel_debug(code, "L后后半段计算出错:{}", str(e))
        return can_cancel, cancel_data, extra_msg
        return can_cancel, cancel_data, extra_msg, cancel_type
    def place_order_success(self, code):
        self.clear(code)
@@ -1756,7 +1893,7 @@
        @return:
        """
        total_datas = local_today_datas.get(code)
        MIN_MONEYS = [300, 200, 100, 50]
        MIN_MONEYS = [300, 200, 100]
        watch_indexes = set()
        for min_money in MIN_MONEYS:
            for i in range(end_index, start_index - 1, -1):
@@ -1841,8 +1978,9 @@
            if tool.trade_time_sub(total_datas[-1]["val"]["time"],
                                   canceled_buyno_map[orderNo]["val"]["time"]) < 10 * 60:
                continue
            val = total_datas[index]["val"]
            time_str = L2DataUtil.get_time_with_ms(val)
            # 统计撤单时间
            cancel_val = canceled_buyno_map[orderNo]["val"]
            time_str = L2DataUtil.get_time_with_ms(cancel_val)
            if time_str not in cancel_time_dict:
                cancel_time_dict[time_str] = set()
            cancel_time_dict[time_str].add(index)
@@ -1886,6 +2024,7 @@
    # L撤触发的代码
    __l_cancel_triggered_codes = set()
    __h_cancel_update_time_cache = {}
    __instance = None
@@ -1931,6 +2070,9 @@
                                                               trade_record_log_util.CancelWatchIndexesInfo.CANCEL_TYPE_H,
                                                               buy_single_index,
                                                               list(indexes)))
        self.__set_watch_indexes(code, indexes)
    def __set_watch_indexes(self, code, indexes):
        CodeDataCacheUtil.set_cache(self.__cancel_watch_indexs_cache, code, indexes)
        key = f"h_cancel_watch_indexs-{code}"
        RedisUtils.setex_async(self.__db, key, tool.get_expire(),
@@ -2051,8 +2193,91 @@
        if watch_indexes or watch_indexes_up:
            watch_indexes |= watch_indexes_up
            self.__save_watch_index_set(code, buy_single_index, watch_indexes)
            self.__h_cancel_update_time_cache[code] = total_datas[-1]["val"]["time"]
            l2_log.h_cancel_debug(code, f"设置监听范围, 数据范围:{real_place_order_index}-{end_index} 监听范围-{watch_indexes}")
        # 设置真实下单位置
    def __remove_cancel_long_time(self, code, buy_single_index):
        """
        删除已经撤单很久的数据
        @param code:
        @return:
        """
        watch_indexes = self.__get_watch_index_set_cache(code)
        if not watch_indexes:
            return
        if code not in self.__h_cancel_update_time_cache or tool.trade_time_sub(tool.get_now_time_str(),
                                                                                self.__h_cancel_update_time_cache[
                                                                                    code]) < 30 * 60:
            # 没有更新过或者更新时间小于30分钟就不更新
            return
        watch_indexes = copy.deepcopy(watch_indexes)
        # 删除撤单半小时之前的数据
        total_datas = local_today_datas.get(code)
        remove_indexes = set()
        for i in watch_indexes:
            cancel_data = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_canceled_data_v2(code,
                                                                                                  i,
                                                                                                  total_datas,
                                                                                                  local_today_canceled_buyno_map.get(
                                                                                                      code))
            if cancel_data and tool.trade_time_sub(total_datas[-1]["val"]["time"],
                                                   cancel_data["val"]["time"]) > 60 * 30:
                # 删除撤单时间30分钟以上的数据
                remove_indexes.add(i)
        if not remove_indexes:
            return
        real_place_order_index = self.__SCancelBigNumComputer.get_real_place_order_index_cache(code)
        if not real_place_order_index:
            return
        transaction_index = self.__transaction_progress_index_dict.get(code)
        if transaction_index is None:
            return
        # 起点为真实下单位置往上数3笔
        start_index = real_place_order_index
        count = 0
        for i in range(real_place_order_index - 1, transaction_index, -1):
            data = total_datas[i]
            val = data['val']
            if not L2DataUtil.is_limit_up_price_buy(val):
                continue
            if float(val['price']) * val['num'] < 50 * 100:
                continue
            left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(code, i,
                                                                                                     total_datas,
                                                                                                     local_today_canceled_buyno_map.get(
                                                                                                         code))
            if left_count > 0:
                count += 1
                start_index = i
                if count >= 3:
                    break
        watch_indexes = watch_indexes - remove_indexes
        # 新增加囊括
        add_indexes = set()
        for i in range(start_index, total_datas[-1]["index"]):
            data = total_datas[i]
            val = data['val']
            if not L2DataUtil.is_limit_up_price_buy(val):
                continue
            if i in watch_indexes:
                continue
            if float(val['price']) * val['num'] < 50 * 100:
                continue
            left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(code, i,
                                                                                                     total_datas,
                                                                                                     local_today_canceled_buyno_map.get(
                                                                                                         code))
            if left_count > 0:
                add_indexes.add(i)
                if len(add_indexes) >= len(remove_indexes):
                    break
        watch_indexes |= add_indexes
        l2_log.h_cancel_debug(code, f"H撤更新:新增索引-{add_indexes} 删除索引-{remove_indexes}")
        self.__save_watch_index_set(code, buy_single_index, watch_indexes)
        # 设置更新时间,
        self.__h_cancel_update_time_cache[code] = total_datas[-1]["val"]["time"]
    def __need_compute_watch_indexes(self, code, transaction_index):
        """
@@ -2129,7 +2354,7 @@
            return
        try:
            # 计算触发位置
            min_num = int(5000 / (float(gpcode_manager.get_limit_up_price(code))))
            min_num = int(5000 / (gpcode_manager.get_limit_up_price_as_num(code)))
            # 统计净涨停买的数量
            not_cancel_indexes = []
            total_datas = local_today_datas.get(code)
@@ -2213,6 +2438,10 @@
            if rate >= threshold_rate:
                l2_log.h_cancel_debug(code, f"撤单比例:{rate}")
                return True, total_data[-1]
        try:
            self.__remove_cancel_long_time(code, buy_single_index)
        except Exception as e:
            l2_log.h_cancel_debug(code, f"更新H撤囊括范围出错:{str(e)}")
        return False, None
    # 下单成功