| | |
| | | |
| | | # 是否有大卖单需要撤 |
| | | 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]: |
| | |
| | | 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) |
| | |
| | | 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)}") |
| | | |
| | |
| | | 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: |
| | |
| | | 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: |
| | | # 将备用订单加进去 |
| | |
| | | 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: |
| | |
| | | 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 |