| | |
| | | # if deal_big_order_info and deal_big_order_info[5] > 5000e4: |
| | | # temp_rate = round(deal_big_order_info[1] / deal_big_order_info[5], 2) |
| | | # threshold_rate = min(max(temp_rate, 0.3), 0.7) |
| | | volume_rate = code_volumn_manager.CodeVolumeManager().get_volume_rate(code)*0.9 |
| | | volume_rate = code_volumn_manager.CodeVolumeManager().get_volume_rate(code) * 0.9 |
| | | threshold_rate = min(max(volume_rate, 0.3), 0.6) |
| | | except: |
| | | pass |
| | |
| | | # 总大卖单成交列表 |
| | | __total_big_sell_order_list_cache = {} |
| | | |
| | | # L后重新囊括的时间 |
| | | __recompute_l_down_time_dict = {} |
| | | |
| | | __instance = None |
| | | |
| | | def __new__(cls, *args, **kwargs): |
| | |
| | | @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: |
| | | trade_record_log_util.add_cancel_watch_indexes_log(code, |
| | | trade_record_log_util.CancelWatchIndexesInfo( |
| | | trade_record_log_util.CancelWatchIndexesInfo.CANCEL_TYPE_L_UP, |
| | | buy_single_index, |
| | | list(indexes))) |
| | | self.__near_by_trade_progress_index_cache[code] = indexes |
| | | RedisUtils.setex_async(self.__db, f"l_cancel_near_by_index-{code}", tool.get_expire(), |
| | | json.dumps(list(indexes))) |
| | | |
| | | def __get_near_by_trade_progress_indexes(self, code): |
| | | val = RedisUtils.get(self.__get_redis(), f"l_cancel_near_by_index-{code}") |
| | | if val is None: |
| | | return None |
| | | return set(json.loads(val)) |
| | | |
| | | def __get_near_by_trade_progress_indexes_cache(self, code): |
| | | cache_result = CodeDataCacheUtil.get_cache(self.__near_by_trade_progress_index_cache, code) |
| | | if cache_result[0]: |
| | | return cache_result[1] |
| | | return None |
| | | |
| | | def __set_cancel_l_down_after_place_order_index(self, code, watch_index, index): |
| | | if code not in self.__cancel_l_down_after_place_order_index_cache: |
| | | self.__cancel_l_down_after_place_order_index_cache[code] = {} |
| | | self.__cancel_l_down_after_place_order_index_cache[code][str(watch_index)] = index |
| | | RedisUtils.setex_async(self.__db, f"l_cancel_down_after_place_order_index-{code}", tool.get_expire(), |
| | | json.dumps(self.__cancel_l_down_after_place_order_index_cache[code])) |
| | | |
| | | def __get_cancel_l_down_after_place_order_index_dict(self, code): |
| | | return self.__cancel_l_down_after_place_order_index_cache.get(code) |
| | | |
| | | def del_watch_index(self, code): |
| | | CodeDataCacheUtil.clear_cache(self.__cancel_watch_index_info_cache, code) |
| | |
| | | logger_debug.exception(e) |
| | | |
| | | # 获取真实下单位后面10笔大单 |
| | | if not is_human: |
| | | # 人为不需要设置 |
| | | watch_indexes_after = self.__compute_l_down_watch_index_after_real_place_order_index(code) |
| | | if watch_indexes_after: |
| | | watch_indexes |= watch_indexes_after |
| | | # if not is_human: |
| | | # # 人为不需要设置 |
| | | # watch_indexes_after = self.__compute_l_down_watch_index_after_real_place_order_index(code) |
| | | # if watch_indexes_after: |
| | | # watch_indexes |= watch_indexes_after |
| | | self.__set_watch_indexes(code, buy_single_index, re_compute, watch_indexes) |
| | | l2_log.l_cancel_debug(code, |
| | | f"设置监听范围({msg}){'(重新计算)' if re_compute else ''}, 数据范围:{re_start_index}-{end_index} 监听范围-{watch_indexes}") |
| | | except Exception as e: |
| | | l2_log.l_cancel_debug(code, f"计算L后囊括范围出错:{str(e)}") |
| | | async_log_util.exception(logger_l2_l_cancel, e) |
| | | |
| | | def __need_update_l_down_after(self, code, start_index, end_index): |
| | | """ |
| | | 是否需要更新l后真实下单位置之后的囊括范围 |
| | | @param code: |
| | | @return: |
| | | """ |
| | | real_place_order_info = self.__real_place_order_index_dict.get(code) |
| | | if not real_place_order_info or real_place_order_info[1]: |
| | | return False |
| | | # 判断L后是否包含后面的数据 |
| | | watch_indexes_info = self.__get_watch_indexes_cache(code) |
| | | if not watch_indexes_info: |
| | | # 没有囊括 |
| | | return False |
| | | watch_indexes = set([int(i) for i in watch_indexes_info[2]]) |
| | | real_place_order_index = real_place_order_info[0] |
| | | for index in watch_indexes: |
| | | if index > real_place_order_index: |
| | | # L后后段已经囊括 |
| | | return False |
| | | # 下单位置之后数10笔买单 |
| | | watch_indexes = set() |
| | | total_datas = local_today_datas.get(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] |
| | | val = data['val'] |
| | | if not L2DataUtil.is_limit_up_price_buy(val): |
| | | continue |
| | | if val['num'] < MIN_NUM: |
| | | continue |
| | | watch_indexes.add(i) |
| | | if len(watch_indexes) >= MAX_COUNT: |
| | | break |
| | | # 看里面的撤单率是否 |
| | | if len(watch_indexes) < MAX_COUNT: |
| | | # 数量不够 |
| | | return False |
| | | # 计算撤单比例是否足够 |
| | | canceled_buyno_map = local_today_canceled_buyno_map.get(code) |
| | | cancel_count = 0 |
| | | for index in watch_indexes: |
| | | # 是否撤单 |
| | | left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2( |
| | | code, index, |
| | | total_datas, |
| | | canceled_buyno_map) |
| | | if left_count <= 0: |
| | | cancel_count += 1 |
| | | if cancel_count > len(watch_indexes) * 0.5: |
| | | return True |
| | | return False |
| | | |
| | | def __compute_l_down_watch_index_after_real_place_order_index(self, code): |
| | | """ |
| | | 计算L后真实下单位置之后的监控索引 |
| | | @return: |
| | | """ |
| | | watch_indexes = set() |
| | | total_datas = local_today_datas.get(code) |
| | | is_ge_code = tool.is_ge_code(code) |
| | | try: |
| | | # 真实下单位置后面的数据就只看大单 |
| | | 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]: |
| | | # 从真实下单位往后找 |
| | | after_count = 0 |
| | | for i in range(real_place_order_info[0] + 1, total_datas[-1]['index'] + 1): |
| | | if after_count > 10: |
| | | break |
| | | 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: |
| | | after_count += 1 |
| | | if l2_data_util.is_big_money(val, is_ge_code): |
| | | watch_indexes.add(i) |
| | | # 记录索引的位置 |
| | | self.__set_cancel_l_down_after_place_order_index(code, i, after_count - 1) |
| | | except Exception as e: |
| | | pass |
| | | return watch_indexes |
| | | |
| | | def __compute_l_down_watch_index_after_by(self, code): |
| | | """ |
| | | 计算L后后半段大单备用 |
| | | @param code: |
| | | @return: |
| | | """ |
| | | if self.__l_down_after_by_big_order_dict.get(code): |
| | | # 不用重复计算 |
| | | return |
| | | real_place_order_info = self.__real_place_order_index_dict.get(code) |
| | | if not real_place_order_info or real_place_order_info[1]: |
| | | return |
| | | real_place_order_index = real_place_order_info[0] |
| | | total_datas = local_today_datas.get(code) |
| | | limit_up_price = gpcode_manager.get_limit_up_price(code) |
| | | limit_up_price = round(float(limit_up_price), 2) |
| | | bigger_num = l2_data_util.get_big_money_val(limit_up_price, tool.is_ge_code(code)) // (limit_up_price * 100) |
| | | min_num = 500000 // (limit_up_price * 100) |
| | | index = -1 |
| | | watch_indexes = set() |
| | | if code not in self.__l_down_after_by_big_order_weight_dict: |
| | | self.__l_down_after_by_big_order_weight_dict[code] = {} |
| | | for i in range(real_place_order_index + 1, total_datas[-1]["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: |
| | | if val["num"] >= bigger_num: |
| | | if index < 0: |
| | | # 开始计数 |
| | | index = 0 |
| | | # 加入大单监听 |
| | | self.__l_down_after_by_big_order_weight_dict[code][str(i)] = int(str(index)) |
| | | watch_indexes.add(i) |
| | | if index >= 0: |
| | | index += 1 |
| | | if index > 10: |
| | | break |
| | | self.__l_down_after_by_big_order_dict[code] = watch_indexes |
| | | l2_log.l_cancel_debug(code, f"L后后半段大单备用囊括范围:{watch_indexes}") |
| | | |
| | | try: |
| | | watch_indexes_info = self.get_l_down_watch_indexes_cache(code) |
| | | if watch_indexes_info: |
| | | total_watch_indexes = set(watch_indexes) | set(watch_indexes_info[2]) |
| | | trade_record_log_util.add_cancel_watch_indexes_log(code, |
| | | trade_record_log_util.CancelWatchIndexesInfo( |
| | | trade_record_log_util.CancelWatchIndexesInfo.CANCEL_TYPE_L_DOWN, |
| | | watch_indexes_info[0], |
| | | list(total_watch_indexes))) |
| | | except: |
| | | pass |
| | | |
| | | # 设置真实下单位置 |
| | | def set_real_place_order_index(self, code, index, buy_single_index=None, is_default=False): |
| | |
| | | |
| | | # 计算范围内的成交位临近未撤大单 |
| | | def __compute_trade_progress_near_by_indexes(self, code, buy_single_index, start_index, end_index): |
| | | if start_index is None or end_index is None: |
| | | return |
| | | total_datas = local_today_datas.get(code) |
| | | MIN_MONEY = 99 * 100 |
| | | MAX_COUNT = 15 |
| | | watch_indexes = set() |
| | | total_num = 0 |
| | | # thresh_hold_money = l2_trade_factor.L2PlaceOrderParamsManager.get_base_m_val(code) |
| | | # threshold_num = thresh_hold_money // (float(gpcode_manager.get_limit_up_price(code)) * 100) |
| | | 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 float(val['price']) * val['num'] < MIN_MONEY: |
| | | 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: |
| | | total_num += val['num'] * left_count |
| | | watch_indexes.add(i) |
| | | if len(watch_indexes) >= MAX_COUNT: |
| | | break |
| | | |
| | | changed = True |
| | | l_up_compute_info = self.__last_l_up_compute_info.get(code) |
| | | if l_up_compute_info: |
| | | if l_up_compute_info[1] == watch_indexes: |
| | | changed = False |
| | | # 保存数据 |
| | | if changed: |
| | | threshold_time = 1 if tool.is_sz_code(code) else 2 |
| | | if l_up_compute_info and l_up_compute_info[1]: |
| | | if time.time() - l_up_compute_info[0] < threshold_time: |
| | | l2_log.l_cancel_debug(code, f"L前监控更新太频繁:{threshold_time}") |
| | | return |
| | | l2_log.l_cancel_debug(code, f"L前监控范围:{watch_indexes} 计算范围:{start_index}-{end_index}") |
| | | self.__set_near_by_trade_progress_indexes(code, buy_single_index, watch_indexes) |
| | | self.__last_l_up_compute_info[code] = (time.time(), watch_indexes) |
| | | pass |
| | | |
| | | # 计算L后还没成交的手数 |
| | | def __compute_total_l_down_not_deal_num(self, code): |
| | | # 只有真实获取到下单位置后才开始计算 |
| | | |
| | | try: |
| | | if code in self.__total_l_down_not_deal_num_dict and time.time() - \ |
| | | self.__total_l_down_not_deal_num_dict[code][ |
| | |
| | | if total_datas is None: |
| | | return |
| | | |
| | | if not self.__is_l_down_can_cancel(code, buy_single_index): |
| | | # L后已经不能守护 |
| | | l2_log.l_cancel_debug(code, f"L后已经无法生效:buy_single_index-{buy_single_index}") |
| | | |
| | | HourCancelBigNumComputer().start_compute_watch_indexes(code, buy_single_index) |
| | | try: |
| | | # 计算L后后半段大单监控范围 |
| | | self.__compute_l_down_watch_index_after_by(code) |
| | | except Exception as e: |
| | | l2_log.l_cancel_debug(code, "__compute_l_down_watch_index_after_by出错") |
| | | |
| | | real_place_order_index_info = self.__real_place_order_index_dict.get(code) |
| | | real_place_order_index = None |
| | | if real_place_order_index_info: |
| | |
| | | return |
| | | # 重新囊括1笔 |
| | | real_place_order_info = self.__real_place_order_index_dict.get(code) |
| | | 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 / gpcode_manager.get_limit_up_price_as_num(code)) |
| | |
| | | watch_indexes.add(data["index"]) |
| | | l2_log.l_cancel_debug(code, f"L后有成交重新囊括:成交索引-{index} 囊括索引-{data['index']}") |
| | | break |
| | | # 从真实下单位置往后囊括大单 |
| | | try: |
| | | left_count_after = 0 |
| | | for j in range(real_place_order_info[0] + 1, total_datas[-1]["index"]): |
| | | data = total_datas[j] |
| | | val = data['val'] |
| | | if left_count_after > 10: |
| | | break |
| | | 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, |
| | | j, |
| | | total_datas, |
| | | local_today_canceled_buyno_map.get( |
| | | code)) |
| | | if left_count > 0: |
| | | left_count_after += 1 |
| | | if l2_data_util.is_big_money(val, is_ge_code) and j not in watch_indexes: |
| | | watch_indexes.add(j) |
| | | l2_log.l_cancel_debug(code, f"L后有成交后半段增加囊括:{j}") |
| | | self.__set_cancel_l_down_after_place_order_index(code, j, left_count_after - 1) |
| | | break |
| | | except: |
| | | pass |
| | | |
| | | self.__set_watch_indexes(code, watch_indexes_info[0], watch_indexes_info[1], watch_indexes) |
| | | |
| | | def __compute_l_down_canceled_rate(self, code, total_data): |
| | |
| | | if not watch_indexes_info: |
| | | return 0, [] |
| | | |
| | | # 这是下单位置之后的索引: key为字符串 |
| | | after_place_order_index_dict = self.__get_cancel_l_down_after_place_order_index_dict(code) |
| | | if after_place_order_index_dict is None: |
| | | after_place_order_index_dict = {} |
| | | after_place_order_index_by_dict = self.__l_down_after_by_big_order_weight_dict.get(code) |
| | | 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: |
| | | # 将备用订单加进去 |
| | | watch_indexes_by = self.__l_down_after_by_big_order_dict.get(code) |
| | | if watch_indexes_by: |
| | | # 是否是下单30分钟内 |
| | | real_place_order_info = self.__real_place_order_index_dict.get(code) |
| | | if real_place_order_info and tool.trade_time_sub(total_data[-1]["val"]["time"], |
| | | total_data[real_place_order_info[0]]["val"][ |
| | | "time"]) < 30 * 60: |
| | | # 下单30分钟内有效 |
| | | watch_indexes |= watch_indexes_by |
| | | else: |
| | | # 清除备用大单 |
| | | watch_indexes_by.clear() |
| | | except Exception as e: |
| | | l2_log.l_cancel_debug(code, "将L2后后半段备用大单加入计算出错:{}", str(e)) |
| | | # 计算监听的总条数 |
| | | total_num = 0 |
| | | # 超大单的手数 |
| | |
| | | |
| | | thresh_hold_rate, must_buy, cancel_rate_info = LCancelRateManager.get_cancel_rate(code) |
| | | for wi in watch_indexes: |
| | | if str(wi) in after_place_order_index_dict: |
| | | # 如果加红就需要计算分母 |
| | | if must_buy: |
| | | total_num += total_data[wi]["val"]["num"] * ( |
| | | 10 - after_place_order_index_dict[str(wi)]) // 10 |
| | | continue |
| | | elif str(wi) in after_place_order_index_by_dict: |
| | | if must_buy: |
| | | total_num += total_data[wi]["val"]["num"] * ( |
| | | 10 - after_place_order_index_by_dict[str(wi)]) // 10 |
| | | continue |
| | | # 超过超大单就算超大单 |
| | | if total_data[wi]["val"]["num"] < super_big_num_thresold: |
| | | total_num += total_data[wi]["val"]["num"] |
| | |
| | | cancel_data = L2DataComputeUtil.is_canceled(code, wi, total_data, canceled_buyno_map, |
| | | dealing_info[0] if dealing_info else None, |
| | | deal_order_nos) |
| | | if str(wi) in after_place_order_index_dict: |
| | | # 真实下单位置之后的按照权重比例来计算 |
| | | if cancel_data: |
| | | canceled_num += total_data[wi]["val"]["num"] * ( |
| | | 10 - after_place_order_index_dict[str(wi)]) // 10 |
| | | elif str(wi) in after_place_order_index_by_dict: |
| | | if cancel_data: |
| | | canceled_num += total_data[wi]["val"]["num"] * ( |
| | | 10 - after_place_order_index_by_dict[str(wi)]) // 10 |
| | | else: |
| | | before_nums_info.append((wi, val["num"])) |
| | | if cancel_data: |
| | | before_canceled_nums_info.append((wi, val['num'])) |
| | | canceled_num += total_data[wi]["val"]["num"] |
| | | |
| | | before_nums_info.append((wi, val["num"])) |
| | | if cancel_data: |
| | | before_canceled_nums_info.append((wi, val['num'])) |
| | | canceled_num += total_data[wi]["val"]["num"] |
| | | if cancel_data: |
| | | canceled_data_indexes.append(cancel_data["index"]) |
| | | rate = round(canceled_num / total_num, 3) |
| | |
| | | if not watch_indexes_info: |
| | | return False, None |
| | | |
| | | # 这是下单位置之后的索引: key为字符串 |
| | | after_place_order_index_dict = self.__get_cancel_l_down_after_place_order_index_dict(code) |
| | | if after_place_order_index_dict is None: |
| | | after_place_order_index_dict = {} |
| | | after_place_order_index_by_dict = self.__l_down_after_by_big_order_weight_dict.get(code) |
| | | 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: |
| | | # 将备用订单加进去 |
| | | watch_indexes_by = self.__l_down_after_by_big_order_dict.get(code) |
| | | if watch_indexes_by: |
| | | # 是否是下单30分钟内 |
| | | real_place_order_info = self.__real_place_order_index_dict.get(code) |
| | | if real_place_order_info and tool.trade_time_sub(total_data[-1]["val"]["time"], |
| | | total_data[real_place_order_info[0]]["val"][ |
| | | "time"]) < 30 * 60: |
| | | # 下单30分钟内有效 |
| | | watch_indexes |= watch_indexes_by |
| | | else: |
| | | # 清除备用大单 |
| | | watch_indexes_by.clear() |
| | | except Exception as e: |
| | | l2_log.l_cancel_debug(code, "将L2后后半段备用大单加入计算出错:{}", str(e)) |
| | | # 计算监听的总条数 |
| | | total_num = 0 |
| | | max_num, max_num_count = 0, 0 |
| | | thresh_hold_rate, must_buy, cancel_rate_info = LCancelRateManager.get_cancel_rate(code) |
| | | super_big_num_thresold = int(2e7 / gpcode_manager.get_limit_up_price_as_num(code) / 100) |
| | | for wi in watch_indexes: |
| | | if str(wi) in after_place_order_index_dict: |
| | | continue |
| | | elif str(wi) in after_place_order_index_by_dict: |
| | | continue |
| | | if total_data[wi]["val"]["num"] < super_big_num_thresold: |
| | | total_num += total_data[wi]["val"]["num"] |
| | | else: |
| | |
| | | trade_index = None |
| | | canceled_buyno_map = local_today_canceled_buyno_map.get(code) |
| | | |
| | | # 如果撤单比例设置为100%就不需要计算下单位后面的订单 |
| | | need_compute_after = False if thresh_hold_rate - 1.00 >= -0.0001 else True |
| | | |
| | | dealing_info = HuaXinBuyOrderManager.get_dealing_order_info(code) |
| | | canceled_watch_indexes = set() |
| | | for wi in watch_indexes: |
| | |
| | | dealing_info[0] if dealing_info else None, |
| | | deal_order_nos) |
| | | if cancel_data: |
| | | if str(wi) in after_place_order_index_dict: |
| | | if not need_compute_after: |
| | | continue |
| | | # 真实下单位置之后的按照权重比例来计算 |
| | | canceled_num += total_data[wi]["val"]["num"] * ( |
| | | 10 - after_place_order_index_dict[str(wi)]) // 10 |
| | | elif str(wi) in after_place_order_index_by_dict: |
| | | if not need_compute_after: |
| | | continue |
| | | canceled_num += total_data[wi]["val"]["num"] * ( |
| | | 10 - after_place_order_index_by_dict[str(wi)]) // 10 |
| | | else: |
| | | canceled_num += total_data[wi]["val"]["num"] |
| | | canceled_num += total_data[wi]["val"]["num"] |
| | | canceled_watch_indexes.add(wi) |
| | | canceled_indexes.append(cancel_data["index"]) |
| | | # if wi == watch_indexes_list[-1] and left_count == 0: |
| | | # # 离下单位置最近的一个撤单,必须触发撤单 |
| | | # l2_log.l_cancel_debug(code, f"计算范围:{start_index}-{end_index},临近撤单:{wi}") |
| | | # return True, total_data[-1] |
| | | |
| | | rate = round(canceled_num / total_num, 3) |
| | | if rate > 1: |
| | | rate = 1 |
| | | # 除开最大单的影响权重 |
| | | # if not must_buy: |
| | | # temp_thresh_hold_rate = round((total_num - max_num * max_num_count) * 0.8 / total_num, 2) |
| | | # if thresh_hold_rate > temp_thresh_hold_rate: |
| | | # if cancel_rate_info and cancel_rate_info[1] > 0: |
| | | # pass |
| | | # else: |
| | | # # 没有人为设置 |
| | | # # 目标撤单比例大于大单撤单比例就取比例均值 |
| | | # thresh_hold_rate = round((thresh_hold_rate + temp_thresh_hold_rate) / 2, 2) |
| | | |
| | | real_place_order_info = self.__real_place_order_index_dict.get(code) |
| | | is_default_place_order_index = real_place_order_info[1] if real_place_order_info else False |
| | | if is_default_place_order_index and not cancel_rate_info[1]: |
| | | # 人为设置的不能取最小 |
| | | 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}, 大卖单成交:{total_sell_nums}手") |
| | | f"L后计算范围:{start_index}-{end_index},已撤单比例:{rate}/{thresh_hold_rate}, 最大单-({max_num},{max_num_count}), 人为设置-{cancel_rate_info}, 真实下单位-{real_place_order_info}, 大卖单成交:{total_sell_nums}手") |
| | | l2_log.l_cancel_debug(code, f"L后已撤手数:{canceled_num}/{total_num} 撤单索引:{canceled_watch_indexes}") |
| | | if rate >= thresh_hold_rate: |
| | | canceled_indexes.sort() |
| | |
| | | return True, total_data[canceled_indexes[-1]] |
| | | |
| | | return False, None |
| | | |
| | | def __compute_near_by_trade_progress_need_cancel(self, code, buy_exec_index, start_index, end_index, total_data, |
| | | is_first_code): |
| | | # L前守护时间为3分钟 |
| | | if tool.trade_time_sub(total_data[-1]['val']['time'], |
| | | total_data[buy_exec_index]['val']['time']) > constant.L_CANCEL_UP_EXPIRE_TIME: |
| | | return False, None |
| | | |
| | | watch_indexes = self.__get_near_by_trade_progress_indexes_cache(code) |
| | | if not watch_indexes: |
| | | return False, None |
| | | |
| | | # 监听范围小于5笔不生效 |
| | | if len(watch_indexes) < 5: |
| | | return False, None |
| | | |
| | | # 计算监听的总条数 |
| | | # 权重 |
| | | WATCH_INDEX_WEIGHTS = [3, 2, 1] |
| | | total_count_weight = 0 |
| | | for wi in range(0, len(watch_indexes)): |
| | | if wi < len(WATCH_INDEX_WEIGHTS): |
| | | total_count_weight += WATCH_INDEX_WEIGHTS[wi] |
| | | else: |
| | | total_count_weight += WATCH_INDEX_WEIGHTS[-1] |
| | | # 判断撤单中是否有监听中的索引 |
| | | need_compute = False |
| | | for i in range(start_index, end_index + 1): |
| | | data = total_data[i] |
| | | val = data["val"] |
| | | if L2DataUtil.is_limit_up_price_buy_cancel(val): |
| | | # 查询买入位置 |
| | | buy_index = l2_data_source_util.L2DataSourceUtils.get_buy_index_with_cancel_data_v2(data, |
| | | local_today_buyno_map.get( |
| | | code)) |
| | | if buy_index is not None and buy_index in watch_indexes: |
| | | need_compute = True |
| | | break |
| | | if need_compute: |
| | | watch_indexes_list = list(watch_indexes) |
| | | watch_indexes_list.sort() |
| | | # 计算撤单比例 |
| | | canceled_count_weight = 0 |
| | | canceled_indexes = [] |
| | | for wi in watch_indexes: |
| | | canceled_data = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_canceled_data_v2(code, |
| | | wi, |
| | | total_data, |
| | | local_today_canceled_buyno_map.get( |
| | | code)) |
| | | if canceled_data: |
| | | canceled_indexes.append(canceled_data["index"]) |
| | | # 获取索引权重 |
| | | pos_index = watch_indexes_list.index(wi) |
| | | if pos_index < len(WATCH_INDEX_WEIGHTS): |
| | | canceled_count_weight += WATCH_INDEX_WEIGHTS[pos_index] |
| | | else: |
| | | canceled_count_weight += WATCH_INDEX_WEIGHTS[-1] |
| | | rate = round(canceled_count_weight / total_count_weight, 3) |
| | | thresh_cancel_rate, must_buy, cancel_rate_info = 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: |
| | | # 计算成交进度位置到当前下单位置的纯买额 |
| | | real_place_order_index_info = self.__real_place_order_index_dict.get(code) |
| | | trade_progress_index, is_default = TradeBuyQueue().get_traded_index(code) |
| | | if trade_progress_index is None: |
| | | trade_progress_index = 0 |
| | | if real_place_order_index_info and trade_progress_index: |
| | | total_num = 0 |
| | | 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 // (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'] |
| | | if not L2DataUtil.is_limit_up_price_buy(val): |
| | | continue |
| | | canceled_data = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_canceled_data_v2(code, |
| | | i, |
| | | total_data, |
| | | local_today_canceled_buyno_map.get( |
| | | code)) |
| | | if not canceled_data: |
| | | # 没有撤单 |
| | | total_num += val["num"] * data["re"] |
| | | 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}") |
| | | return False, None |
| | | |
| | | canceled_indexes.sort() |
| | | 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 add_big_sell_order_deal_list(self, code, deal_order_list): |
| | | """ |
| | |
| | | total_datas = local_today_datas.get(code) |
| | | 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): |
| | | watch_indexes_info = self.__get_watch_indexes_cache(code) |
| | | if not watch_indexes_info: |
| | | return True |
| | | trade_index, is_default = TradeBuyQueue().get_traded_index(code) |
| | | if trade_index is None: |
| | | trade_index = 0 |
| | | if trade_index is None: |
| | | return True |
| | | real_place_order_index_info = self.__real_place_order_index_dict.get(code) |
| | | if not real_place_order_index_info: |
| | | return True |
| | | |
| | | # 计算已经成交的比例 |
| | | total_datas = local_today_datas.get(code) |
| | | total_deal_nums = 0 |
| | | total_nums = 1 |
| | | for index in watch_indexes_info[2]: |
| | | # 不能计算L后后半段 |
| | | if index > real_place_order_index_info[0]: |
| | | continue |
| | | data = total_datas[index] |
| | | val = data["val"] |
| | | left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(code, |
| | | index, |
| | | total_datas, |
| | | local_today_canceled_buyno_map.get( |
| | | code)) |
| | | total_nums += val["num"] |
| | | if left_count > 0 and index < trade_index: |
| | | total_deal_nums += val["num"] |
| | | thresh_hold_rate, must_buy, cancel_rate_info = 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: |
| | |
| | | logger_l2_l_cancel.exception(e) |
| | | raise e |
| | | extra_msg = "L后" |
| | | # 不需要计算L前 |
| | | # if not can_cancel: |
| | | # # 成交位临近撤 |
| | | # try: |
| | | # can_cancel, cancel_data = self.__compute_near_by_trade_progress_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_UP |
| | | # extra_msg = "L前" |
| | | # except Exception as e: |
| | | # logger_l2_l_cancel.exception(e) |
| | | # raise e |
| | | |
| | | try: |
| | | if self.__need_update_l_down_after(code, start_index, end_index): |
| | | # 更新后半段 |
| | | watch_indexes = self.__compute_l_down_watch_index_after_real_place_order_index(code) |
| | | if watch_indexes: |
| | | l2_log.l_cancel_debug(code, "L后后半段囊括:{}", watch_indexes) |
| | | watch_indexes_info = self.__get_watch_indexes_cache(code) |
| | | if watch_indexes_info and watch_indexes_info[2]: |
| | | # 没有囊括 |
| | | watch_indexes |= set(watch_indexes_info[2]) |
| | | self.__set_watch_indexes(code, watch_indexes_info[0], watch_indexes_info[1], watch_indexes) |
| | | except Exception as e: |
| | | l2_log.l_cancel_debug(code, "L后后半段计算出错:{}", str(e)) |
| | | |
| | | return can_cancel, cancel_data, extra_msg, cancel_type |
| | | |
| | | def place_order_success(self, code): |
| | |
| | | fdatas.append(item) |
| | | fdatas.sort(key=lambda x: x[0]) |
| | | return fdatas |
| | | |
| | | # def statistic_total_big_order_info(self, code): |
| | | # """ |
| | | # 统计L后的大单信息 |
| | | # @param code: |
| | | # @return: 囊括金额列表, 成交金额列表, 撤单金额列表, 待成交列表 |
| | | # """ |
| | | # trade_index, is_default = TradeBuyQueue().get_traded_index(code) |
| | | # if trade_index is None: |
| | | # trade_index = 0 |
| | | # real_place_order_index_info = self.__real_place_order_index_dict.get(code) |
| | | # if not real_place_order_index_info: |
| | | # return None |
| | | # total_datas = local_today_datas.get(code) |
| | | # # 统计囊括,已成,已撤,待成交 |
| | | # all_indexes = set() |
| | | # deal_indexes = set() |
| | | # canceled_indexes = set() |
| | | # not_deal_indexes = set() |
| | | # big_money_threshold = l2_data_util.get_big_money_val(gpcode_manager.get_limit_up_price_as_num(code), tool.is_ge_code(code)) |
| | | # big_num_threshold = int(big_money_threshold/gpcode_manager.get_limit_up_price_as_num(code)/100) |
| | | # for index in range(0,total_datas[-1]): |
| | | # data = total_datas[index] |
| | | # val = data["val"] |
| | | # if val['num']<big_num_threshold: |
| | | # continue |
| | | # if not L2DataUtil.is_limit_up_price_buy(val): |
| | | # continue |
| | | # all_indexes.add(index) |
| | | # left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(code, |
| | | # index, |
| | | # total_datas, |
| | | # local_today_canceled_buyno_map.get( |
| | | # code)) |
| | | # if left_count == 0: |
| | | # canceled_indexes.add(index) |
| | | # continue |
| | | # if index < trade_index: |
| | | # deal_indexes.add(index) |
| | | # continue |
| | | # not_deal_indexes.add(index) |
| | | # all_money_list = [int(float(total_datas[x]['val']['price'] * total_datas[x]['val']['num'] * 100)) for x in |
| | | # all_indexes] |
| | | # deal_money_list = [int(float(total_datas[x]['val']['price'] * total_datas[x]['val']['num'] * 100)) for x in |
| | | # deal_indexes] |
| | | # canceled_money_list = [int(float(total_datas[x]['val']['price'] * total_datas[x]['val']['num'] * 100)) for x in |
| | | # canceled_indexes] |
| | | # not_deal_money_list = [int(float(total_datas[x]['val']['price'] * total_datas[x]['val']['num'] * 100)) for x in |
| | | # not_deal_indexes] |
| | | # return all_money_list, deal_money_list, canceled_money_list, not_deal_money_list |
| | | |
| | | def statistic_l_down_watch_indexes_info(self, code): |
| | | """ |