Administrator
2024-07-19 b5434ba1edc4a1733a37ba27d8107478077ea350
cancel_strategy/s_l_h_cancel_strategy.py
@@ -339,10 +339,18 @@
    # 是否有大卖单需要撤
    def __need_cancel_for_big_sell_order(self, code, big_sell_order_info, order_begin_pos: OrderBeginPosInfo):
        """
        @param code:
        @param big_sell_order_info:(总卖金额,[(卖单号,总手数,价格,('开始时间',买单号),('结束时间',买单号)),...])
        @param order_begin_pos:
        @return:
        """
        # 需要排除成交时间在下单时间之前的
        total_deal_money = 0
        max_single_deal_money = 0  # 最大单笔卖金额
        total_datas = local_today_datas.get(code)
        real_order_index_info = self.__get_real_place_order_index_info_cache(code)
        # 下单时间
        real_order_time_ms = None
        real_order_index = None
        if real_order_index_info and not real_order_index_info[1]:
@@ -355,9 +363,11 @@
            if real_order_time_ms:
                if tool.trade_time_sub_with_ms(deal_time, real_order_time_ms) >= 0:
                    m = x[1] * x[2]
                    max_single_deal_money = max(max_single_deal_money, m)
                    total_deal_money += m
            else:
                m = x[1] * x[2]
                max_single_deal_money = max(max_single_deal_money, m)
                total_deal_money += m
        zyltgb = l2_trade_factor.L2TradeFactorUtil.get_zyltgb(code)
@@ -369,43 +379,45 @@
        if total_deal_money >= threshold_big_deal:
            # S重砸必撤的金额满足以后,以前是无脑撤。现在优化一下,看成交进度位---真实下单位的区间额≤重砸金额*3.3倍,就撤。
            try:
                # 上证,下单3分钟内
                try:
                    if tool.is_sh_code(code) and real_order_index is not None and tool.trade_time_sub(
                            total_datas[-1]["val"]["time"], total_datas[real_order_index]["val"]["time"]) < 3 * 60:
                        # 上证如果重砸额大于阈值的1.5倍直接撤单
                        if not gpcode_manager.MustBuyCodesManager().is_in_cache(code):
                            if total_deal_money >= threshold_big_deal * 1.5:
                                return True, f"1s内成交({total_deal_money}) 大于大卖单({threshold_big_deal})的1.5倍"
                            # 如果没有大单成交也直接撤单
                            deal_big_order_count = BigOrderDealManager().get_total_buy_count(code)
                            if deal_big_order_count < 1:
                                return True, f"1s内成交({total_deal_money}) 大于大卖单({threshold_big_deal})且无大单成交"
                except Exception as e:
                    l2_log.s_cancel_debug(code, "S重砸出错了:{}", str(e))
                # 单笔重砸
                if max_single_deal_money >= threshold_big_deal:
                    # 上证,下单3分钟内
                    try:
                        if tool.is_sh_code(code) and real_order_index is not None and tool.trade_time_sub(
                                total_datas[-1]["val"]["time"], total_datas[real_order_index]["val"]["time"]) < 3 * 60:
                            # 上证如果重砸额大于阈值的1.5倍直接撤单
                            if not gpcode_manager.MustBuyCodesManager().is_in_cache(code):
                                if total_deal_money >= threshold_big_deal * 1.5:
                                    return True, f"1s内成交({total_deal_money}) 大于大卖单({threshold_big_deal})的1.5倍"
                                # 如果没有大单成交也直接撤单
                                deal_big_order_count = BigOrderDealManager().get_total_buy_count(code)
                                if deal_big_order_count < 1:
                                    return True, f"1s内成交({total_deal_money}) 大于大卖单({threshold_big_deal})且无大单成交"
                    except Exception as e:
                        l2_log.s_cancel_debug(code, "S重砸出错了:{}", str(e))
                need_compute = False
                trade_index, is_default = TradeBuyQueue().get_traded_index(code)
                if trade_index is None:
                    trade_index = 0
                if real_order_index_info and not real_order_index_info[1]:
                    need_compute = True
                    need_compute = False
                    trade_index, is_default = TradeBuyQueue().get_traded_index(code)
                    if trade_index is None:
                        trade_index = 0
                    if real_order_index_info and not real_order_index_info[1]:
                        need_compute = True
                if need_compute:
                    total_count, total_num = L2DataComputeUtil.compute_left_buy_order(code, trade_index,
                                                                                      real_order_index_info[0],
                                                                                      limit_up_price)
                    if total_num == 0:
                        total_num = 1
                    if need_compute:
                        total_count, total_num = L2DataComputeUtil.compute_left_buy_order(code, trade_index,
                                                                                          real_order_index_info[0],
                                                                                          limit_up_price)
                        if total_num == 0:
                            total_num = 1
                    threshold_rate, threshold_rate_msg = SCancelRateManager.get_threshhold_rate(code,
                                                                                                SCancelRateManager.TYPE_S_FAST_BIG)
                        threshold_rate, threshold_rate_msg = SCancelRateManager.get_threshhold_rate(code,
                                                                                                    SCancelRateManager.TYPE_S_FAST_BIG)
                    if total_deal_money / (total_num * limit_up_price * 100) >= threshold_rate:
                        # 大单成交额占总剩余总囊括的30%
                        return True, f"1s内大于{threshold_big_deal}({threshold_rate_msg})大卖单({total_deal_money})"
                else:
                    return True, f"1s内大于{threshold_big_deal}大卖单({total_deal_money})"
                        if total_deal_money / (total_num * limit_up_price * 100) >= threshold_rate:
                            # 大单成交额占总剩余总囊括的30%
                            return True, f"1s内大于{threshold_big_deal}({threshold_rate_msg})大卖单({total_deal_money})"
                    else:
                        return True, f"1s内大于{threshold_big_deal}大卖单({total_deal_money})"
            except Exception as e:
                l2_log.info(code, logger_debug, f"S快计算出错:{str(e)}")
@@ -732,6 +744,33 @@
        if cache_result[0]:
            return cache_result[1]
        return None
    def get_l_down_watch_indexes_cache(self, code):
        """
        获取L后的监听范围
        @param code:
        @return:(buy_single_index, re_compute, indexes)
        """
        return self.__get_watch_indexes_cache(code)
    def get_real_place_order_index_info(self, code):
        """
        获取真实下单索引信息
        @param code:
        @return:(index, is_default)
        """
        return self.__real_place_order_index_dict.get(code)
    def set_l_down_watch_index_info(self, code, buy_single_index, re_compute: int, indexes):
        """
        设置l后索引
        @param code:
        @param buy_single_index:
        @param re_compute:
        @param indexes:
        @return:
        """
        self.__set_watch_indexes(code, buy_single_index, re_compute, indexes)
    def __set_near_by_trade_progress_indexes(self, code, buy_single_index, indexes):
        if indexes:
@@ -1362,7 +1401,6 @@
        if after_place_order_index_by_dict is None:
            after_place_order_index_by_dict = {}
        watch_indexes = set([int(i) for i in watch_indexes_info[2]])
        try:
            # 将备用订单加进去
@@ -1398,7 +1436,6 @@
                    total_num += total_data[wi]["val"]["num"] * (
                            10 - after_place_order_index_by_dict[str(wi)]) // 10
                continue
            total_num += total_data[wi]["val"]["num"] * total_data[wi]["re"]
            if total_data[wi]["val"]["num"] > max_num:
@@ -1660,6 +1697,158 @@
        print(self.__get_cancel_l_down_after_place_order_index_dict(code))
class LCancelOutOfDateWatchIndexesManager:
    """
    L撤过期数据更新
    """
    __latest_cancel_time_dict = {}
    @classmethod
    def compute_latest_canceled_watch_index_time(cls, code, watch_indexes):
        """
        获取 最近撤单的索引
        @param code:
        @param watch_indexes:
        @return:
        """
        total_datas = local_today_datas.get(code)
        canceled_buyno_map = local_today_canceled_buyno_map.get(code)
        max_cancel_index = -1
        for index in watch_indexes:
            orderNo = total_datas[index]["val"]["orderNo"]
            canceled_data = canceled_buyno_map.get(str(orderNo))
            if canceled_data:
                max_cancel_index = max(max_cancel_index, canceled_data["index"])
        if max_cancel_index < 0:
            # 没有撤单的
            return None
        return total_datas[max_cancel_index]["val"]["time"]
    @classmethod
    def compute_l_down_common_watch_indexes(cls, code, start_index, end_index, max_count, min_num, exclude_watch_indexes):
        """
        获取L后监听数据
        @param code:
        @param re_start_index:
        @param end_index:
        @param max_count:
        @return:
        """
        total_datas = local_today_datas.get(code)
        MIN_MONEYS = [300, 200, 100, 50]
        watch_indexes = set()
        for min_money in MIN_MONEYS:
            for i in range(end_index, start_index - 1, -1):
                try:
                    data = total_datas[i]
                    val = data['val']
                    if not L2DataUtil.is_limit_up_price_buy(val):
                        continue
                    # 小金额过滤
                    if float(val['price']) * val['num'] < min_money * 100:
                        continue
                    if val['num'] < min_num:
                        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 and i not in exclude_watch_indexes:
                        watch_indexes.add(i)
                        if len(watch_indexes) >= max_count:
                            break
                except Exception as e:
                    logger_l2_l_cancel.error(f"{code}: 范围: {start_index}-{end_index}  位置:{i}")
                    logger_l2_l_cancel.exception(e)
            if len(watch_indexes) >= max_count:
                break
        return watch_indexes
    def process(self, code, start_index, end_index):
        # 获取监听数据
        watch_indexes_info = LCancelBigNumComputer().get_l_down_watch_indexes_cache(code)
        if not watch_indexes_info:
            return
        if watch_indexes_info[1]:
            # 已经重新计算过就不再执行
            return
        watch_indexes = set(watch_indexes_info[2])
        # 获取真实下单位数据
        real_place_order_index_info = LCancelBigNumComputer().get_real_place_order_index_info(code)
        if not real_place_order_index_info or real_place_order_index_info[1]:
            return
        real_place_order_index = real_place_order_index_info[0]
        total_datas = local_today_datas.get(code)
        # 计算最近的撤单时间
        buyno_map = local_today_buyno_map.get(code)
        # 已经改过了就不需要修改
        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 str(val["orderNo"]) not in buyno_map:
                continue
            buy_index = buyno_map[str(val["orderNo"])]["index"]
            if buy_index in watch_indexes and real_place_order_index > buy_index:
                # 下单位之前的L后囊括范围的订单被撤单
                self.__latest_cancel_time_dict[code] = val["time"]
        if tool.trade_time_sub(total_datas[-1]["val"]["time"],
                               total_datas[real_place_order_index]["val"]["time"]) < 10 * 60:
            # 下单10分钟后才能生效
            return
        if code not in self.__latest_cancel_time_dict:
            return
        if tool.trade_time_sub(total_datas[-1]["val"]["time"], self.__latest_cancel_time_dict.get(code)) < 10 * 60:
            # 最近的撤单时间小于10分钟
            return
        # TODO 查找是否有相同时间的撤单且撤单时间在10分钟之前
        canceled_buyno_map = local_today_canceled_buyno_map.get(code)
        cancel_time_dict={}
        for index in watch_indexes:
            if index > real_place_order_index:
                continue
            orderNo = str(total_datas[index]["val"]["orderNo"])
            if orderNo not in canceled_buyno_map:
                continue
            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)
            if time_str not in cancel_time_dict:
                cancel_time_dict[time_str] = set()
            cancel_time_dict[time_str].add(index)
        remove_indexes = set()
        for t in  cancel_time_dict:
            if len(cancel_time_dict[t])>1:
                remove_indexes|=cancel_time_dict[t]
        if remove_indexes:
            # 移除索引
            add_count = len(remove_indexes)
            limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
            min_num = int(5000/limit_up_price)
            trade_index, is_default = TradeBuyQueue().get_traded_index(code)
            if trade_index is None:
                trade_index = 0
            add_watch_index = self.compute_l_down_common_watch_indexes(code,trade_index ,real_place_order_index, add_count, min_num, watch_indexes)
            watch_indexes -= remove_indexes
            watch_indexes|=add_watch_index
            # 保存数据 /
            LCancelBigNumComputer().set_l_down_watch_index_info(code, watch_indexes_info[0], True, watch_indexes)
            l2_log.l_cancel_debug(code, f"L后稳定后更新监控范围:删除-{remove_indexes} 增加-{add_watch_index}")
# --------------------------------H撤-------------------------------
class HourCancelBigNumComputer:
    __db = 0