| | |
| | | # 上一次的L后的统计信息 |
| | | __last_l_down_watch_index_statistic_info = {} |
| | | |
| | | # 总大卖单成交列表 |
| | | __total_big_sell_order_list_cache = {} |
| | | |
| | | __instance = None |
| | | |
| | | def __new__(cls, *args, **kwargs): |
| | |
| | | return cls.__redis_manager.getRedis() |
| | | |
| | | def __set_watch_indexes(self, code, buy_single_index, re_compute: int, indexes): |
| | | if code in self.__total_big_sell_order_list_cache: |
| | | self.__total_big_sell_order_list_cache.pop(code) |
| | | self.__cancel_watch_index_info_cache[code] = (buy_single_index, re_compute, indexes) |
| | | RedisUtils.delete_async(self.__db, f"l_cancel_watch_index_info-{code}") |
| | | RedisUtils.setex_async(self.__db, f"l_cancel_watch_index_info-{code}", tool.get_expire(), |
| | |
| | | |
| | | def clear(self, code=None): |
| | | if code: |
| | | if code in self.__total_big_sell_order_list_cache: |
| | | self.__total_big_sell_order_list_cache.pop(code) |
| | | LDownCancelWatchIndexStatisticManager().remove_statistic_info(code) |
| | | self.del_watch_index(code) |
| | | if code in self.__l_down_after_by_big_order_dict: |
| | |
| | | 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]]) |
| | | |
| | | # 判断本批次是否有大单, 如果没大单就不更新了 |
| | | if is_human and watch_indexes: |
| | | try: |
| | | watch_num_list = [total_datas[x]['val']['num'] for x in watch_indexes] |
| | | max_num = max(watch_num_list) |
| | | if max_num < BIG_ORDER_NUM_THRESHOLD: |
| | | l2_log.l_cancel_debug(code, f"人为更新监听L后无大单,忽略本次囊括:{watch_indexes}") |
| | | return |
| | | if round(max_num / sum(watch_num_list), 2) > 0.5: |
| | | l2_log.l_cancel_debug(code, f"最大单占比超过50%,忽略本次囊括:{watch_indexes}") |
| | | return |
| | | except Exception as e: |
| | | logger_debug.exception(e) |
| | | |
| | | # 获取真实下单位后面10笔大单 |
| | | if not is_human: |
| | | # 人为不需要设置 |
| | |
| | | rate = round(canceled_num / total_num, 3) |
| | | return rate, canceled_data_indexes, (before_nums_info, before_canceled_nums_info) |
| | | |
| | | def __compute_need_cancel(self, code, buy_exec_index, start_index, end_index, total_data, is_first_code): |
| | | def __compute_need_cancel(self, code, buy_exec_index, start_index, end_index, total_data, is_first_code, force_compute=False): |
| | | """ |
| | | L后撤单; |
| | | 撤单计算规则:计算撤单比例时,将真实下单位置之后的数据按权重(离下单位最近的权重越大)加入分子,不加入分母(总囊括手数)计算 |
| | |
| | | if buy_index is not None and buy_index in watch_indexes: |
| | | need_compute = True |
| | | break |
| | | if force_compute: |
| | | need_compute=True |
| | | if need_compute: |
| | | # =====计算本批次大卖单成交量==== |
| | | sell_nos = set() |
| | | total_sell_nums = 0 |
| | | try: |
| | | if code in self.__total_big_sell_order_list_cache: |
| | | for d in self.__total_big_sell_order_list_cache[code]: |
| | | if d[0] in sell_nos: |
| | | continue |
| | | sell_nos.add(d[0]) |
| | | total_sell_nums += d[1] |
| | | # 获取正在成交的大卖单 |
| | | dealing_sell_order_info=HuaXinSellOrderStatisticManager.get_dealing_order_info(code) |
| | | if dealing_sell_order_info and dealing_sell_order_info[2]>=299e4: |
| | | total_sell_nums += dealing_sell_order_info[1] |
| | | total_sell_nums=total_sell_nums//100 |
| | | except Exception as e: |
| | | l2_log.l_cancel_debug(code, f"计算总卖大单出错:{str(e)}") |
| | | |
| | | # 计算撤单比例 |
| | | watch_indexes_list = list(watch_indexes) |
| | | watch_indexes_list.sort() |
| | | canceled_num = 0 |
| | | canceled_num = total_sell_nums # 将成交的大卖单计入已撤金额 |
| | | # 记录撤单索引 |
| | | canceled_indexes = [] |
| | | |
| | |
| | | # 人为设置的不能取最小 |
| | | thresh_hold_rate = min(0.49, thresh_hold_rate) |
| | | l2_log.l_cancel_debug(code, |
| | | f"L后计算范围:{start_index}-{end_index},已撤单比例:{rate}/{thresh_hold_rate}, 下单位之后的索引:{after_place_order_index_dict}, 最大单-({max_num},{max_num_count}), 人为设置-{cancel_rate_info}, 真实下单位-{real_place_order_info}") |
| | | f"L后计算范围:{start_index}-{end_index},已撤单比例:{rate}/{thresh_hold_rate}, 下单位之后的索引:{after_place_order_index_dict}, 最大单-({max_num},{max_num_count}), 人为设置-{cancel_rate_info}, 真实下单位-{real_place_order_info}, 大卖单成交:{total_sell_nums}手") |
| | | if rate >= thresh_hold_rate: |
| | | canceled_indexes.sort() |
| | | l2_log.l_cancel_debug(code, f"L后撤单,撤单位置:{canceled_indexes[-1]}") |
| | |
| | | # L后重新囊括的时间 |
| | | __recompute_l_down_time_dict = {} |
| | | |
| | | def set_big_sell_order_info(self, code, big_sell_order_info): |
| | | def add_big_sell_order_deal_list(self, code, deal_order_list): |
| | | """ |
| | | 设置大卖单信息 |
| | | 添加大单卖成交列表 |
| | | @param code: |
| | | @param big_sell_order_info: |
| | | @return: |
| | | @param deal_order_list:[(卖单号,股数,成交额)] |
| | | @return: 是否可撤单, 撤单数据 |
| | | """ |
| | | if not big_sell_order_info or not big_sell_order_info[0] or not big_sell_order_info[1]: |
| | | return False, "" |
| | | if not deal_order_list: |
| | | return False |
| | | # 添加成交量 |
| | | if code not in self.__total_big_sell_order_list_cache: |
| | | self.__total_big_sell_order_list_cache[code] = [] |
| | | self.__total_big_sell_order_list_cache[code].extend(deal_order_list) |
| | | |
| | | # 计算是否可撤单 |
| | | 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, "" |
| | | return self.__compute_need_cancel(code, 0, total_datas[-1]["index"], total_datas[-1]["index"], total_datas, True, force_compute=True) |
| | | |
| | | # L后是否还有可能撤单 |
| | | def __is_l_down_can_cancel(self, code, buy_exec_index): |