| | |
| | | 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, trade_constant |
| | |
| | | @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) |
| | |
| | | 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) |
| | |
| | | |
| | | # 获取撤单比例,返回(撤单比例,是否必买) |
| | | @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 |
| | |
| | | # 计算的上截至位距离下截至位纯买额要小于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 |
| | |
| | | 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): |
| | |
| | | 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: |
| | |
| | | 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, |
| | |
| | | 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: |
| | |
| | | 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] |
| | |
| | | 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]: |
| | | # 从真实下单位往后找 |
| | |
| | | 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'] |
| | |
| | | # 计算监听的总条数 |
| | | 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: |
| | |
| | | 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: |
| | | # 真实下单位置之后的按照权重比例来计算 |
| | |
| | | 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: |
| | | # # 离下单位置最近的一个撤单,必须触发撤单 |
| | |
| | | # 除开最大单的影响权重 |
| | | 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: |
| | |
| | | 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: |
| | | # 计算成交进度位置到当前下单位置的纯买额 |
| | |
| | | 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'] |
| | |
| | | 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): |
| | |
| | | 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 |
| | |
| | | @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): |
| | |
| | | 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) |