Administrator
4 天以前 48fb7a00951f91bdc707e5dd2d196e5bccb752c3
l2/cancel_buy_strategy.py
@@ -16,17 +16,18 @@
from db import redis_manager_delegate as redis_manager
from db.redis_manager_delegate import RedisUtils
from l2.l2_data_manager import OrderBeginPosInfo
from l2.l2_transaction_data_manager import HuaXinBuyOrderManager
from l2.l2_transaction_data_manager import HuaXinBuyOrderManager, HuaXinSellOrderStatisticManager
from trade.sell.sell_rule_manager import TradeRuleManager
from utils import tool
from l2.transaction_progress import TradeBuyQueue
from trade import trade_queue_manager, l2_trade_factor, trade_manager, trade_data_manager
from l2 import l2_log, l2_data_source_util
from l2 import l2_log, l2_data_source_util, code_price_manager
from l2.l2_data_util import L2DataUtil, local_today_num_operate_map, local_today_datas, local_today_buyno_map, \
    local_today_canceled_buyno_map
from log_module.log import logger_buy_1_volumn
from log_module.log import logger_buy_1_volumn, logger_l2_error
from utils.tool import CodeDataCacheUtil
from settings import trade_setting
def set_real_place_position(code, index, buy_single_index=None, is_default=True):
@@ -40,6 +41,7 @@
    FCancelBigNumComputer().set_real_order_index(code, index, is_default)
    JCancelBigNumComputer().set_real_place_order_index(code, index, buy_single_index, is_default)
    NBCancelBigNumComputer().set_real_place_order_index(code, index, buy_single_index, is_default)
    RDCancelBigNumComputer().set_real_place_order_index(code, index, buy_single_index, is_default)
class BaseCancel:
@@ -124,6 +126,56 @@
                    return i
        return end_index
    @classmethod
    def compute_max_buy_order_info(cls, code, start_index, end_index):
        """
        计算区间最大买单
        @param code:
        @param start_index:
        @param end_index:
        @return:
        """
        total_datas = local_today_datas.get(code)
        canceled_buyno_map = local_today_canceled_buyno_map.get(code)
        max_info = (0, 0)  # 索引,手数
        for i in range(start_index, end_index + 1):
            data = total_datas[i]
            val = data['val']
            if not L2DataUtil.is_limit_up_price_buy(val):
                continue
            left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(code, i,
                                                                                                     total_datas,
                                                                                                     canceled_buyno_map)
            if left_count > 0:
                if val["num"] > max_info[1]:
                    max_info = (i, val["num"])
        return total_datas[max_info[0]]
    @classmethod
    def is_canceled(cls, code, index, total_datas, canceled_buyno_map, trade_index, deal_order_nos):
        """
        是否已经撤单
        @param deal_order_nos: 成交大单集合
        @param trade_index: 成交进度位
        @param index: 索引
        @param code: 代码
        @param total_datas:
        @param canceled_buyno_map:撤单的订单号
        @return:
        """
        cancel_data = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_canceled_data_v2(code, index,
                                                                                              total_datas,
                                                                                              canceled_buyno_map)
        if cancel_data:
            # 已经撤单
            return True
        else:
            if trade_index and trade_index > index:
                # 成交进度大于索引位置,且还没成交
                if total_datas[index]["val"]["orderNo"] not in deal_order_nos:
                    return True
            return False
# ---------------------------------D撤-------------------------------
# 计算 成交位->真实下单位置 总共还剩下多少手没有撤单
@@ -189,11 +241,139 @@
        self.__clear_data(code)
# ---------------------------------RD撤-------------------------------
# 扫入下单大单撤
class RDCancelBigNumComputer:
    __db = 0
    __redis_manager = redis_manager.RedisManager(0)
    __instance = None
    # 下单位之后的封单中的大单
    __watch_indexes_cache = {}
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = super(RDCancelBigNumComputer, cls).__new__(cls, *args, **kwargs)
            cls.__load_datas()
        return cls.__instance
    @classmethod
    def __get_redis(cls):
        return cls.__redis_manager.getRedis()
    @classmethod
    def __load_datas(cls):
        keys = RedisUtils.keys(cls.__get_redis(), "radical_big_order_watch-*")
        for k in keys:
            code = k.split("-")[1]
            val = RedisUtils.get(cls.__get_redis(), k)
            val = json.loads(val)
            cls.__watch_indexes_cache[code] = set(val)
    def set_watch_indexes(self, code, indexes):
        l2_log.d_cancel_debug(code, f"扫入大单监听:{indexes}")
        self.__watch_indexes_cache[code] = set(indexes)
        RedisUtils.setex_async(self.__db, f"radical_big_order_watch-{code}", tool.get_expire(),
                               json.dumps(list(indexes)))
    def set_real_place_order_index(self, code, index, buy_single_index, is_default):
        if is_default:
            return
        if code in self.__watch_indexes_cache and len(self.__watch_indexes_cache[code]) > 1:
            # 囊括的单大于1个
            return
        # 从买入信号位开始囊括
        limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
        min_money = l2_data_util.get_big_money_val(limit_up_price, tool.is_ge_code(code))
        min_num = int(round(min_money / limit_up_price / 100))
        total_datas = local_today_datas.get(code)
        watch_indexes = set()
        for i in range(buy_single_index, index):
            data = total_datas[i]
            val = data["val"]
            if not L2DataUtil.is_limit_up_price_buy(val):
                continue
            if val["num"] < min_num:
                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:
                watch_indexes.add(i)
        if watch_indexes:
            l2_log.d_cancel_debug(code, f"更新扫入大单监听:{watch_indexes}")
            self.__watch_indexes_cache[code] = watch_indexes
    def need_cancel(self, code, start_index, end_index):
        """
        是否需要撤单
        @param code:
        @param start_index:
        @param end_index:
        @return: 是否需要撤单,撤单索引, 消息
        """
        buyno_map = local_today_buyno_map.get(code)
        watch_indexes = self.__watch_indexes_cache.get(code)
        if not watch_indexes:
            return False, None, "无大单监听"
        total_datas = local_today_datas.get(code)
        need_compute = False
        for i in range(start_index, end_index + 1):
            data = total_datas[i]
            val = data["val"]
            if not L2DataUtil.is_limit_up_price_buy_cancel(val):
                continue
            if val["num"] * float(val["price"]) < 5000:
                continue
            buy_index = l2_data_source_util.L2DataSourceUtils.get_buy_index_with_cancel_data_v2(data, buyno_map)
            if buy_index is None:
                continue
            if buy_index in watch_indexes:
                need_compute = True
                break
        cancel_indexes = set()
        canceled_buyno_map = local_today_canceled_buyno_map.get(code)
        if need_compute or True:
            cancel_count = 0
            cancel_data = None
            # 成交买单号
            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
            for index in watch_indexes:
                if L2DataComputeUtil.is_canceled(code, index, total_datas, canceled_buyno_map, trade_index,
                                                 deal_order_nos):
                    # 买单已撤单
                    cancel_count += 1
                    cancel_indexes.add(index)
            rate = round(cancel_count / len(watch_indexes), 2)
            if rate >= 0.8:
                return True, cancel_data, f"撤单比例-{rate},大单撤单({cancel_indexes})"
        return False, None, "无大单撤单"
    def __clear_data(self, code):
        if code in self.__watch_indexes_cache:
            self.__watch_indexes_cache.pop(code)
            RedisUtils.delete_async(self.__db, f"radical_big_order_watch-{code}")
    def clear_data(self, code):
        self.__clear_data(code)
# 新F撤,根据成交数据来撤
class FCancelBigNumComputer:
    __db = 0
    __redis_manager = redis_manager.RedisManager(0)
    __real_order_index_cache = {}
    __max_buy_order_num_cache = {}
    # 下单距离太远计算
    __far_away_computed_cache = {}
    __instance = None
@@ -245,6 +425,8 @@
    def clear(self, code=None):
        if code:
            self.__del_real_order_index(code)
            if code in self.__max_buy_order_num_cache:
                self.__max_buy_order_num_cache.pop(code)
        else:
            keys = RedisUtils.keys(self.__get_redis(), "f_cancel_real_order_index-*")
            if keys:
@@ -255,12 +437,28 @@
    # 设置真实的下单位置
    def set_real_order_index(self, code, index, is_default):
        self.__set_real_order_index(code, index, is_default)
        self.__far_away_computed_cache[code] = False
        # if not is_default and code.find("60") == 0:
        try:
            # 统计未成交的最大单
            trade_index = 0
            trade_info = TradeBuyQueue().get_traded_index(code)
            if trade_info and not trade_info[1] and trade_info[0] is not None:
                trade_index = trade_info[0]
            data = L2DataComputeUtil.compute_max_buy_order_info(code, trade_index, index)
            # 保存最大单
            self.__max_buy_order_num_cache[code] = data["val"]["num"]
            l2_log.f_cancel_debug(code, f"最大单计算:索引-{data['index']} 范围:{trade_index}-{index}")
        except Exception as e:
            logger_l2_error.exception(e)
    def place_order_success(self, code):
        self.clear(code)
    def cancel_success(self, code):
        self.clear(code)
        # 撤单成功之后就清除当前的成交
        HuaXinSellOrderStatisticManager.clear_latest_deal_volume(code)
    def __get_fast_deal_threshold_value(self, code, place_order_time_str):
        """
@@ -269,9 +467,9 @@
        @param place_order_time_str:下单时间
        @return:(金额(单位:W),笔数)
        """
        max60, yesterday = code_volumn_manager.get_histry_volumn(code)
        max60, yesterday = code_volumn_manager.CodeVolumeManager().get_histry_volumn(code)
        if max60:
            money_y = code_volumn_manager.get_reference_volume_as_money_y(code)
            money_y = code_volumn_manager.CodeVolumeManager().get_reference_volume_as_money_y(code)
            money = int(200 * money_y + 280)
            if tool.trade_time_sub(place_order_time_str, "10:00:00") <= 0:
                # 10点前下单打7折
@@ -305,6 +503,23 @@
        # 是否是下单1分钟内
        if tool.trade_time_sub(tool.get_now_time_str(), total_datas[real_order_index]['val']['time']) > 1 * 60:
            return False, "下单超过60s"
        try:
            if code in self.__max_buy_order_num_cache:
                max_num = self.__max_buy_order_num_cache[code]
                if max_num and tool.is_ge_code(code):
                    max_num = max_num * 6.6
                details = HuaXinSellOrderStatisticManager.get_latest_3s_continue_deal_volumes(code)
                threshold_num = int(max_num * 0.5 * 100)
                count = 0
                for d in details:
                    if d[1] > threshold_num:
                        count += 1
                if count >= 2:
                    return True, f"连续3秒有2s抛压过大:{details} 最大值:{max_num}"
        except Exception as e:
            l2_log.f_cancel_debug(code, f"大抛压撤单计算出错:{str(e)}")
        # 查询最近2秒成交是否超过阈值
        THRESHOLD_MONEY_W, THRESHOLD_COUNT = self.__get_fast_deal_threshold_value(code,
                                                                                  total_datas[real_order_index]['val'][
@@ -335,18 +550,26 @@
                if dealing_info and str(dealing_info[0]) == str(val["orderNo"]):
                    total_left_num -= dealing_info[1] // 100
        limit_up_price = gpcode_manager.get_limit_up_price(code)
        if total_left_count <= 1 or (total_left_count <= THRESHOLD_COUNT and limit_up_price and total_left_num * float(
                limit_up_price) < THRESHOLD_MONEY_W * 100):
            return True, f"剩余笔数({total_left_count})/金额({round(total_left_num * float(limit_up_price) * 100)})不足,成交进度:{trade_index},真实下单位置:{real_order_index} 阈值:({THRESHOLD_MONEY_W},{THRESHOLD_COUNT}) "
        total_left_money = total_left_num * float(limit_up_price) * 100
        if total_left_money < 1e8:
            if total_left_count <= 1 or (
                    total_left_count <= THRESHOLD_COUNT and limit_up_price and total_left_num * float(
                    limit_up_price) < THRESHOLD_MONEY_W * 100):
                return True, f"剩余笔数({total_left_count})/金额({round(total_left_num * float(limit_up_price) * 100)})不足,成交进度:{trade_index},真实下单位置:{real_order_index} 阈值:({THRESHOLD_MONEY_W},{THRESHOLD_COUNT}) "
        return False, f"不满足撤单条件: 成交进度-{trade_index} 真实下单位置-{real_order_index} total_left_count-{total_left_count} total_left_num-{total_left_num}"
    # 距离太近,封单不足,有大单50w大单砸下来就撤
    def need_cancel_for_p(self, code, big_sell_order_info, order_begin_pos):
    # 距离太近,封单不足
    def need_cancel_for_p(self, code, order_begin_pos):
        if True:
            return False, ""
        if gpcode_manager.MustBuyCodesManager().is_in_cache(code):
            return False, "已加红"
        if not order_begin_pos or not order_begin_pos.buy_exec_index or order_begin_pos.buy_exec_index < 0:
            return False, "尚未下单"
        if big_sell_order_info[0] < 50 * 10000 or not big_sell_order_info[1]:
            return False, "不为大单"
        # 判断是否具有真实的下单位置
        real_order_index_info = self.__get_real_order_index_cache(code)
        if not real_order_index_info:
@@ -358,72 +581,64 @@
        if trade_index is None:
            trade_index = 0
        real_order_index = real_order_index_info[0]
        if real_order_index_info[0] <= trade_index:
        if real_order_index <= trade_index:
            return False, "真实下单位在成交位之前"
        start_order_no = big_sell_order_info[1][-1][4][1]
        real_trade_index = trade_index
        # 统计未撤订单的数量与金额
        total_datas = local_today_datas.get(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
            real_trade_index = i
            break
        # 是否是下单3分钟内
        if tool.trade_time_sub(total_datas[-1]['val']['time'], total_datas[real_order_index]['val']['time']) > 180:
            return False, "下单超过180s"
        sub_time = tool.trade_time_sub(total_datas[-1]['val']['time'], total_datas[real_order_index]['val']['time'])
        if sub_time > 60:
            return False, "下单超过60s"
        limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
        # 判断累计大单数量
        min_money = l2_data_util.get_big_money_val(limit_up_price, tool.is_ge_code(code))
        total_count, total_num = L2DataComputeUtil.compute_left_buy_order(code, trade_index, real_order_index,
                                                                          limit_up_price, min_money)
        total_left_count = 0
        # 下单后3秒,排撤比例≥65%则撤掉,视为P撤的一种,排得太后了。
        # if sub_time > 3 and not self.__far_away_computed_cache.get(code):
        #     self.__far_away_computed_cache[code] = True
        #     # 成交进度位到真实下单位的位置过远
        #     total_count_, total_num_ = L2DataComputeUtil.compute_left_buy_order(code, trade_index, real_order_index,
        #                                                                         limit_up_price, 500000)
        #     # 获取买1金额
        #     buy1_money = code_price_manager.Buy1PriceManager().get_latest_buy1_money(code)
        #     if buy1_money:
        #         if total_num_ * limit_up_price * 100 > buy1_money * 0.65:
        #             return True, f"P撤:成交位置距离下单位置太远 成交位-{trade_index} 下单位-{real_order_index} 买1-{buy1_money}"
        min_time_s, max_time_s = 2, 60
        # if total_num * limit_up_price >= 299 * 100:
        #     min_time_s, max_time_s = 30, 60
        if sub_time <= min_time_s:
            return False, f"下单在{min_time_s}s内"
        if sub_time > max_time_s:
            return False, f"下单超过{max_time_s}s"
        # 计算我们后面的大单与涨停纯买额
        total_left_num = 0
        # 成交位到真实下单位剩余的未成交的单
        for i in range(real_trade_index + 1, real_order_index_info[0]):
        total_big_num_count = 0
        canceled_buyno_map = local_today_canceled_buyno_map.get(code)
        for i in range(real_order_index + 1, len(total_datas)):
            data = total_datas[i]
            val = data["val"]
            if not L2DataUtil.is_limit_up_price_buy(val):
                continue
            if val["num"] * float(val["price"]) < 5000:
            money = val["num"] * float(val["price"]) * 100
            if money < 500000:
                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))
                                                                                                     canceled_buyno_map)
            if left_count > 0:
                total_left_count += left_count
                total_left_num += val["num"] * left_count
        limit_up_price = gpcode_manager.get_limit_up_price(code)
        if total_left_count < 5 or total_left_num * float(limit_up_price) < 500 * 100:
            # 距离成交进度位5笔以内或500万以内
            # 计算我们后面的大单与涨停纯买额
            total_left_num = 0
            total_big_num_count = 0
            for i in range(real_order_index + 1, len(total_datas)):
                data = total_datas[i]
                val = data["val"]
                if not L2DataUtil.is_limit_up_price_buy(val):
                    continue
                money = val["num"] * float(val["price"])
                if money < 5000:
                    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:
                    if money > 299 * 100:
                        total_big_num_count += 1
                    total_left_num += val["num"]
            left_money = total_left_num * float(limit_up_price)
            if total_big_num_count == 0 or left_money < 1000 * 100:
                # 实际下单位后方所有涨停纯买额≤1000万或没有任何大单(≥299万)
                return True, f"P撤:封单纯买额-{round(left_money / 100, 1)}万 大单数量-{total_big_num_count} 下单位-{real_order_index} 成交位-{real_trade_index}"
                if money >= min_money:
                    total_big_num_count += 1
                total_left_num += val["num"]
        left_money = total_left_num * float(limit_up_price)
        if left_money < 1000 * 100 or total_big_num_count < 2:
            # 实际下单位后方所有涨停纯买额≤1000万
            return True, f"P撤:封单纯买额-{round(left_money / 100, 1)}万 剩余大单数量-{total_big_num_count} 下单位-{real_order_index}"
        return False, "不满足撤单条件"
    # w撤
@@ -445,19 +660,21 @@
        total_datas = local_today_datas.get(code)
        if tool.trade_time_sub(total_datas[-1]['val']['time'], total_datas[real_order_index]['val']['time']) > 60:
            return False, "超过守护时间"
        limit_up_price = round(float(gpcode_manager.get_limit_up_price(code)), 2)
        limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
        end_index = L2DataComputeUtil.compute_end_index(code, real_order_index + 1, total_datas[-1]["index"],
                                                        limit_up_price, 10)
        # 从成交进度位到截至位置计算大单
        min_money = l2_data_util.get_big_money_val(limit_up_price)
        min_money = l2_data_util.get_big_money_val(limit_up_price, tool.is_ge_code(code))
        left_count, left_money = L2DataComputeUtil.compute_left_buy_order(code, trade_index, end_index, limit_up_price,
                                                                          min_money=min_money)
        if left_count < 1:
            return True, f"范围:{real_order_index}-{end_index}  大单数量:{left_count}"
            return True, f"范围:{trade_index}-{end_index}  大单数量:{left_count}"
        return False, "大单数量够"
# ---------------------------------G撤-------------------------------
# 已不效
class GCancelBigNumComputer:
    __real_place_order_index_dict = {}
    __trade_progress_index_dict = {}
@@ -580,7 +797,28 @@
        total_datas = local_today_datas.get(code)
        watch_indexes = set()
        for i in range(start_index, real_order_index):
        # G撤的囊括范围向后面延申5笔
        end_index = real_order_index
        count = 0
        for i in range(real_order_index + 1, total_datas[-1]["index"] + 1):
            data = total_datas[i]
            val = data["val"]
            if not L2DataUtil.is_limit_up_price_buy(val):
                continue
            if val["num"] * float(val["price"]) < 5000:
                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:
                continue
            count += 1
            if count > 5:
                break
            end_index = i
        for i in range(start_index, end_index + 1):
            # 判断是否有未撤的大单
            data = total_datas[i]
            val = data["val"]
@@ -595,13 +833,15 @@
                                                                                                         code))
            if left_count > 0:
                watch_indexes.add(i)
        if watch_indexes:
            # 还有300万以上的大单没有撤单
            if from_real_order_index_changed or recompute:
                # 真实下单位改变后才会更新
                final_watch_indexes = origin_watch_index | watch_indexes
                self.__watch_indexes_dict[code] = final_watch_indexes
                l2_log.g_cancel_debug(code, f"大单监听:{final_watch_indexes} 是否重新计算:{recompute}")
                l2_log.g_cancel_debug(code,
                                      f"大单监听:{final_watch_indexes} 是否重新计算:{recompute} 计算范围:{start_index}-{end_index}")
                # 有大单监听,需要移除之前的小单监听
                if code in self.__watch_indexes_by_dict:
                    self.__watch_indexes_by_dict[code].clear()
@@ -717,8 +957,8 @@
                    canceled_indexes.add(cancel_data["index"])
            cancel_rate = round(len(canceled_indexes) / len(watch_indexes), 2)
            threshhold_rate = constant.G_CANCEL_RATE
            situation = trade_manager.MarketSituationManager().get_situation_cache()
            if situation == trade_manager.MarketSituationManager.SITUATION_GOOD:
            situation = trade_setting.MarketSituationManager().get_situation_cache()
            if situation == trade_setting.MarketSituationManager.SITUATION_GOOD:
                threshhold_rate = constant.G_CANCEL_RATE_FOR_GOOD_MARKET
            if cancel_rate > threshhold_rate:
                canceled_indexes_list = list(canceled_indexes)
@@ -736,8 +976,8 @@
                    canceled_indexes.add(cancel_data["index"])
            cancel_rate = round(len(canceled_indexes) / len(watch_indexes_by), 2)
            threshhold_rate = constant.G_CANCEL_RATE
            situation = trade_manager.MarketSituationManager().get_situation_cache()
            if situation == trade_manager.MarketSituationManager.SITUATION_GOOD:
            situation = trade_setting.MarketSituationManager().get_situation_cache()
            if situation == trade_setting.MarketSituationManager.SITUATION_GOOD:
                threshhold_rate = constant.G_CANCEL_RATE_FOR_GOOD_MARKET
            if cancel_rate > threshhold_rate:
                canceled_indexes_list = list(canceled_indexes)
@@ -749,6 +989,8 @@
    # B撤单
    # 剩余一个大单撤半截就撤单
    def need_cancel_for_b(self, code, start_index, end_index):
        if gpcode_manager.MustBuyCodesManager().is_in_cache(code):
            return False, None, "已加红"
        real_place_order_info = self.__real_place_order_index_dict.get(code)
        if not real_place_order_info or real_place_order_info[1]:
            # 没有真实下单位置
@@ -895,14 +1137,18 @@
            start_index = traded_index + 1
        total_datas = local_today_datas.get(code)
        watch_indexes = set()
        for i in range(start_index, real_order_index):
        # 查找成交进度位到真实下单位置所有的索引
        watch_indexes_info = []
        limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
        big_num = int(l2_data_util.get_big_money_val(limit_up_price, tool.is_ge_code(code)) / (limit_up_price * 100))
        for i in range(start_index, real_order_index + 1):
            # 判断是否有未撤的大单
            data = total_datas[i]
            val = data["val"]
            if not L2DataUtil.is_limit_up_price_buy(val):
                continue
            if val["num"] * float(val["price"]) < 29900:
            if val["num"] < big_num:
                continue
            # 是否已撤单
            left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(code, i,
@@ -910,14 +1156,28 @@
                                                                                                     local_today_canceled_buyno_map.get(
                                                                                                         code))
            if left_count > 0:
                watch_indexes.add(i)
                watch_indexes_info.append((i, val["num"]))
        # 当所有大单≤6笔时则G撤全部囊括
        #  大单>6笔时囊括其三分之一
        if len(watch_indexes_info) > 6:
            watch_indexes = set([x[0] for x in watch_indexes_info[:int(round(len(watch_indexes_info) / 3, 0))]])
            # 找出最大单
            max_info = watch_indexes_info[0]
            for mi in watch_indexes_info:
                if mi[1] > max_info[1]:
                    max_info = mi
            watch_indexes.add(max_info[0])
        else:
            watch_indexes = set([x[0] for x in watch_indexes_info])
        if watch_indexes:
            # 还有300万以上的大单没有撤单
            if from_real_order_index_changed or recompute:
                # 真实下单位改变后才会更新
                final_watch_indexes = origin_watch_index | watch_indexes
                self.__set_watch_index(code, final_watch_indexes)
                l2_log.g_cancel_debug(code, f"大单监听:{final_watch_indexes} 是否重新计算:{recompute}")
                l2_log.g_cancel_debug(code,
                                      f"大单监听:{final_watch_indexes} 是否重新计算:{recompute} 计算范围:{start_index}-{real_order_index}")
    def set_trade_progress(self, code, buy_single_index, index):
        # if self.__trade_progress_index_dict.get(code) != index:
@@ -967,8 +1227,8 @@
                    canceled_indexes.add(cancel_data["index"])
            cancel_rate = round(len(canceled_indexes) / len(watch_indexes), 2)
            threshhold_rate = constant.G_CANCEL_RATE
            situation = trade_manager.MarketSituationManager().get_situation_cache()
            if situation == trade_manager.MarketSituationManager.SITUATION_GOOD:
            situation = trade_setting.MarketSituationManager().get_situation_cache()
            if situation == trade_setting.MarketSituationManager.SITUATION_GOOD:
                threshhold_rate = constant.G_CANCEL_RATE_FOR_GOOD_MARKET
            if gpcode_manager.MustBuyCodesManager().is_in_cache(code):
                threshhold_rate = constant.G_CANCEL_RATE_WITH_MUST_BUY
@@ -1314,7 +1574,7 @@
            self.__set_l2_second_money_record(code, t_, time_dict_num[t_], time_dict_num_index[t_]["s"],
                                              time_dict_num_index[t_]["e"])
        print("保存涨停封单额时间:", round(time.time() * 1000) - start_time)
        # print("保存涨停封单额时间:", round(time.time() * 1000) - start_time)
        # 累计最新的金额
        total_num, index = self.__get_l2_latest_money_record(code)
@@ -1434,7 +1694,7 @@
        if not with_cancel:
            cancel_index = None
        print("封单额计算时间:", round(time.time() * 1000) - start_time)
        # print("封单额计算时间:", round(time.time() * 1000) - start_time)
        process_end_index = end_index
        if cancel_index:
            process_end_index = cancel_index
@@ -1675,7 +1935,7 @@
            if not outoftime:
                # 上次计算还未超时
                return
        limit_up_price = round(float(gpcode_manager.get_limit_up_price(code)), 2)
        limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
        if cancel_single_info and outoftime:
            # 更新需要计算信号
@@ -1734,7 +1994,7 @@
            return False, None, "超过生效时间"
        buyno_map = local_today_buyno_map.get(code)
        limit_up_price = round(float(gpcode_manager.get_limit_up_price(code)), 2)
        limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
        min_volume = 50 * 10000 // int(limit_up_price * 100)
        # 计算纯买额
        for i in range(start_index, end_index + 1):
@@ -1797,13 +2057,15 @@
        self.__real_place_order_index_info_dict[code] = (index, is_default)
    def need_cancel(self, code, trade_index):
        if gpcode_manager.MustBuyCodesManager().is_in_cache(code):
            return False, "已加红"
        # [时间, 真实下单位置, 信号总手数, 目前手数, 最新计算的索引]
        real_place_order_index_info = self.__real_place_order_index_info_dict.get(code)
        if not real_place_order_index_info or real_place_order_index_info[1]:
            return False, "没有找到真实下单位"
        real_place_order_index = real_place_order_index_info[0]
        limit_up_price = round(float(gpcode_manager.get_limit_up_price(code)), 2)
        limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
        if limit_up_price < 3:
            return False, "股价小于3块"