""" 买入策略帮助类 """ import time from code_attribute import gpcode_manager, code_volumn_manager from l2 import l2_data_util, l2_data_source_util, transaction_progress from l2.l2_data_util import L2DataUtil from l2.l2_transaction_data_manager import HuaXinSellOrderStatisticManager from log_module import async_log_util from log_module.log import logger_l2_error from settings.trade_setting import MarketSituationManager, TradeBlockBuyModeManager from trade import trade_data_manager from utils import tool, buy_condition_util, global_util def is_has_small_batch_cancel(code, start_index, end_index): """ 是否有小群撤单:有连续10笔涨停撤单且连续10笔涨停撤单中小于2笔涨停买单 @param code: @param total_datas: @param start_index: @param end_index: @return: """ # 从end_index找到start_index limit_up_price = gpcode_manager.get_limit_up_price_as_num(code) min_num = int(round(5000 / limit_up_price)) total_datas = l2_data_util.local_today_datas.get(code) end_time_with_ms = l2_data_util.L2DataUtil.get_time_with_ms(total_datas[end_index]["val"]) buy_count = 0 cancel_count = 0 for i in range(end_index - 1, start_index, -1): data = total_datas[i] val = data["val"] if val["num"] < min_num: continue if not l2_data_util.L2DataUtil.is_limit_up_price_buy_cancel(val): if l2_data_util.L2DataUtil.is_limit_up_price_buy(val): if cancel_count > 0: # 当统计到一个涨停买撤的时候才能统计买 buy_count += 1 if buy_count > 1: break continue # 与当前时间相差3s的结束 if tool.trade_time_sub_with_ms(end_time_with_ms, l2_data_util.L2DataUtil.get_time_with_ms(val)) > 10000: break cancel_count += 1 if cancel_count >= 10: break if cancel_count >= 10 and buy_count < 2: return True return False def is_cancel_rate_reieved(code, threshhold_rate, start_index, end_index): """ 撤单比例是否达到某一个阈值 @param code: @param threshhold_rate: @param start_index: @param end_index: @return: """ # 统计总共的涨停买 limit_up_price = gpcode_manager.get_limit_up_price_as_num(code) min_num = int(round(5000 / limit_up_price)) total_datas = l2_data_util.local_today_datas.get(code) buyno_map = l2_data_util.local_today_buyno_map.get(code) buy_count = 0 for i in range(start_index, end_index): data = total_datas[i] val = data["val"] if not l2_data_util.L2DataUtil.is_limit_up_price_buy(val): continue if val["num"] < min_num: continue buy_count += 1 # 统计总共的涨停买撤 cancel_count = 0 for i in range(start_index, end_index): data = total_datas[i] val = data["val"] if not l2_data_util.L2DataUtil.is_limit_up_price_buy_cancel(val): continue if val["num"] < min_num: continue buy_index = l2_data_source_util.L2DataSourceUtils.get_buy_index_with_cancel_data_v2(data, buyno_map) if buy_index and start_index <= buy_index: cancel_count += 1 if buy_count == 0: return False, "买入数量为0" if round(cancel_count / buy_count, 2) > threshhold_rate: return True, f"买入数量-{buy_count} 撤单数量-{cancel_count}" return False, f"买入数量-{buy_count} 撤单数量-{cancel_count}" def is_far_away_from_trade_index(code, trade_index, buy1_money): """ 是否距离成交进度位太远 @param code: @param trade_index: @param buy1_money: @return: """ if buy1_money < 1e7: # 买1大于1千万才能计算 return False limit_up_price = gpcode_manager.get_limit_up_price_as_num(code) min_num = int(round(5000 / limit_up_price)) threshhold_num = int(round(buy1_money * 0.5 / 100 / limit_up_price)) total_datas = l2_data_util.local_today_datas.get(code) end_index = total_datas[-1]["index"] total_num = 0 canceled_buyno_map = l2_data_util.local_today_canceled_buyno_map.get( code) for i in range(trade_index, end_index + 1): 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, canceled_buyno_map) if left_count > 0: total_num += val["num"] if total_num > threshhold_num: return True return False def is_near_by_trade_index(code, trade_index): """ 是否距离成交位近 @param code: @param trade_index: @return: """ # 获取今日成交量与参考量 # today = get_today_volumn(code) # max60, yesterday = get_histry_volumn(code) try: today_volume = code_volumn_manager.CodeVolumeManager().get_today_volumn_cache(code) histry_volumn = code_volumn_manager.CodeVolumeManager().get_histry_volumn(code) if not today_volume or not histry_volumn: return False, "尚未获取到量" threshhold_volume = (histry_volumn[0][0] - today_volume) // 3 limit_up_price = gpcode_manager.get_limit_up_price_as_num(code) threshhold_volumes = threshhold_volume // 100, int(50000 / limit_up_price), int(200000 / limit_up_price) total_data = l2_data_util.local_today_datas.get(code) total_count = 0 total_big_count = 0 total_num = 0 for i in range(trade_index + 1, total_data[-1]["index"] + 1): data = total_data[i] val = data["val"] if not l2_data_util.L2DataUtil.is_limit_up_price_buy(val): continue money = val["num"] * float(val["price"]) if money < 5000: continue left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2( code, i, total_data, l2_data_util.local_today_canceled_buyno_map.get( code)) if left_count > 0: total_num += val["num"] total_count += 1 if money > 29900: total_big_count += 1 if threshhold_volumes[2] < total_num: break if threshhold_volumes[1] <= total_num <= threshhold_volumes[2] and total_num < threshhold_volumes[ 0] and total_big_count > 0: # 剩余的值在500w-2000w之间才会参与计算 return True, "" return False, f"未成交手数-{total_num},阈值-{threshhold_volumes[0]},大单数量-{total_big_count}" except Exception as e: async_log_util.error(logger_l2_error, f"计算是否距离成交进度位置近:{str(e)}") return False, "计算异常" def is_quantization(code, start_index, end_index): """ 是否是量化单 @param code: @param satrt_index: @param end_index: @return:(是否是量化, 下次可以下单时间) """ # 阈值的取值范围 THRESHOLD_MONEY_RANGE = 1e5, 3e5 today_volume = code_volumn_manager.CodeVolumeManager().get_today_volumn_cache(code) histry_volumn = code_volumn_manager.CodeVolumeManager().get_histry_volumn(code) if not today_volume or not histry_volumn: return False, "尚未获取到量" threshhold_volume = (histry_volumn[0][0] - today_volume) // 6 // 100 limit_up_price = gpcode_manager.get_limit_up_price_as_num(code) threshhold_volumes_range = int(THRESHOLD_MONEY_RANGE[0] / limit_up_price), int( THRESHOLD_MONEY_RANGE[1] / limit_up_price) if threshhold_volume < threshhold_volumes_range[0]: threshhold_volume = threshhold_volumes_range[0] if threshhold_volume > threshhold_volumes_range[1]: threshhold_volume = threshhold_volumes_range[1] total_datas = l2_data_util.local_today_datas.get(code) time_as_ms = tool.trade_time_sub_with_ms( L2DataUtil.get_time_with_ms(total_datas[end_index]["val"]), L2DataUtil.get_time_with_ms(total_datas[start_index]["val"])) if time_as_ms > (10 if tool.is_sz_code(code) else 100): return False, "非量化" limit_up_price = gpcode_manager.get_limit_up_price_as_num(code) total_buy_nums = 0 min_num = int(5000 / limit_up_price) # 获取成交进度位 for i in range(start_index, end_index + 1): val = total_datas[i]["val"] if not L2DataUtil.is_limit_up_price_buy(val): continue if val["num"] < min_num: continue total_buy_nums += val["num"] if total_buy_nums > threshhold_volume: break if total_buy_nums > threshhold_volume: # 判断是否为量化 # 深证10ms内,上证100ms内就判定为量化 HuaXinSellOrderStatisticManager.clear_latest_deal_volume(code) next_buy_time = time.time() + buy_condition_util.get_cancel_and_buy_space_time( code) / 1000 # 如果是首次下单,增加一次下单次数 place_order_count = trade_data_manager.PlaceOrderCountManager().get_place_order_count(code) if place_order_count == 0: trade_data_manager.PlaceOrderCountManager().place_order(code) return True, next_buy_time, f"执行位批次数据量({total_buy_nums})大于{threshhold_volume} {start_index}-{end_index}" else: return False, None def is_block_can_buy(code, can_buy_result): """ 板块是否可买 @param code: @param can_buy_result: @return: """ now_timestamp = int(tool.get_now_time_str().replace(":", "")) # 判断板块 # (可以买的板块列表, 是否是独苗, 消息简介,可买的强势主线, 板块关键词) if can_buy_result is None: return False, True, "尚未获取到板块信息" # 是否是强势30分钟 is_in_strong_time_30 = now_timestamp <= int("100000") # 获取市场行情 situation = MarketSituationManager().get_situation_cache() zylt_threshold_as_yi = buy_condition_util.get_zyltgb_threshold(situation) zyltgb_as_yi = round(global_util.zyltgb_map.get(code) / 100000000, 2) if zyltgb_as_yi < zylt_threshold_as_yi[0]: return False, True, f"{zylt_threshold_as_yi[0]}亿以下的都不买({zyltgb_as_yi})" # 测试时可取消注释 # if 1 > 0: # return True, False, "买所有" if zyltgb_as_yi >= zylt_threshold_as_yi[1]: return False, True, f"{zylt_threshold_as_yi[1]}亿以上的都不买({zyltgb_as_yi})" msg_list = [] if is_in_strong_time_30: msg_list.append("强势30分钟") # 独苗 if not can_buy_result[0] and can_buy_result[1]: msg_list.append("独苗") return True, False, "强势30分钟,独苗" elif not can_buy_result[0]: return False, True, f"强势30分钟,非独苗不满足身位:{can_buy_result[2]}" else: msg_list.append("非独苗") # 后排,满足自由流通市值需要下单 return True, False, can_buy_result[2] else: place_order_count = trade_data_manager.PlaceOrderCountManager().get_place_order_count(code) if place_order_count > 0: return True, False, "之前下过单" if not can_buy_result[0]: # 没有板块 if can_buy_result[1]: # 是独苗 if not TradeBlockBuyModeManager().can_buy_unique_block(): # 不能买独苗 return False, True, f"非强势30分钟,独苗,不满足身位:{can_buy_result[2]}" else: # 非独苗,没有可以买入的板块 return False, True, f"非强势30分钟,非独苗,不满足身位:{can_buy_result[2]}" return True, False, can_buy_result[2]