Administrator
2024-08-15 b9404847333a972b55766924ad3aa41aac5fd4f4
下单条件修改
7个文件已修改
347 ■■■■ 已修改文件
huaxin_client/l1_api_client.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/cancel_buy_strategy.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/l2_data_manager_new.py 135 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/l2_transaction_data_processor.py 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/test.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/current_price_process_manager.py 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/buy_strategy_util.py 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
huaxin_client/l1_api_client.py
@@ -39,7 +39,6 @@
                if request_id in self.__result_cache:
                    return self.__result_cache
                time.sleep(0.002)
            print("ReqReqQryShareCalendar:", results)
        except Exception as e:
            logging.exception(e)
l2/cancel_buy_strategy.py
@@ -355,6 +355,8 @@
        try:
            if code in self.__max_buy_order_num_cache:
                max_num = self.__max_buy_order_num_cache[code]
                if max_num and tool.is_ge_code(code):
                    max_num = max_num * 6.6
                details = HuaXinSellOrderStatisticManager.get_latest_3s_continue_deal_volumes(code)
                threshold_num = int(max_num * 0.5 * 100)
                count = 0
l2/l2_data_manager_new.py
@@ -260,6 +260,9 @@
    # 下次买的时间
    __next_buy_time_dict = {}
    # 中断本批次买入数据处理
    __break_current_batch_data_for_buy_dict = {}
    # 获取代码评分
    @classmethod
    def get_code_scores(cls):
@@ -518,6 +521,7 @@
    # 处理未挂单
    @classmethod
    def __process_not_order(cls, code, start_index, end_index, capture_time, is_first_code):
        cls.__break_current_batch_data_for_buy_dict[code] = False
        __start_time = round(t.time() * 1000)
        # 获取阈值
        threshold_money, msg = cls.__get_threshmoney(code)
@@ -728,6 +732,8 @@
                l2_log.debug(code, "不可以下单,原因:{}", reason)
                trade_record_log_util.add_cant_place_order_log(code, reason)
                if need_clear_data:
                    # 中断买入
                    cls.__break_current_batch_data_for_buy_dict[code] = True
                    trade_result_manager.real_cancel_success(code, order_begin_pos.buy_single_index,
                                                             order_begin_pos.buy_exec_index,
                                                             local_today_datas.get(code))
@@ -910,59 +916,67 @@
                if int(limit_up_time.replace(":", "")) < int("093000"):
                    return False, True, f"上证开一09:32之前不下单"
        # ------------挂单时间约束----------
        order_begin_pos = cls.__get_order_begin_pos(
            code)
        if not trade_result_manager.can_place_order_for_cancel_time(code, total_data[order_begin_pos.buy_exec_index]):
            return False, True, f"距离上次挂单小于时间限制"
        # ------------板块约束-------------
        if not cls.__WantBuyCodesManager.is_in_cache(code):
            # 想买单无板块约束
            block_buy_result = buy_strategy_util.is_block_can_buy(code, cls.__get_can_buy_block(code))
            if not block_buy_result[0]:
                return block_buy_result
        if constant.L2_SOURCE_TYPE == constant.L2_SOURCE_TYPE_HUAXIN:
            # ---------------------判断是否为板上放量----------------------
            trade_price = current_price_process_manager.get_trade_price(code)
            if trade_price is None:
                return False, True, f"尚未获取到当前成交价"
            # 判断是否为板上放量:
            # 1.当前成交价为涨停价
            # 2.总卖额为0
            # 2.距离最近的非板上成交的时间大于一个阈值
            if abs(limit_up_price - float(trade_price)) < 0.001:
                # 获取最近的非涨停价成交时间
                not_limit_up_info = current_price_process_manager.get_trade_not_limit_up_info(code)
                if not not_limit_up_info or tool.trade_time_sub(total_data[-1]['val']['time'],
                                                                not_limit_up_info[1]) > 10:
                    # 获取最近2s的成交
                    deal_list = HuaXinSellOrderStatisticManager.get_latest_2s_continue_deal_volumes(code)
                    total_deal_volume = 0
                    if deal_list:
                        total_deal_volume = sum([x[1] for x in deal_list])
                    total_deal_money = int(total_deal_volume * float(limit_up_price))
                    # 获取买1的封单额
                not_limit_up_trade_time_with_ms = current_price_process_manager.get_trade_not_limit_up_time_with_ms(
                    code)
                threshold_time_space = buy_condition_util.get_cancel_and_buy_space_time(code)
                if not not_limit_up_trade_time_with_ms or tool.trade_time_sub_with_ms(
                        L2DataUtil.get_time_with_ms(total_data[-1]['val']),
                        not_limit_up_trade_time_with_ms) >= threshold_time_space:
                    # 判断成交进度到当前数据的笔数,如果少于10笔且还有未成交的大单(>=299)就可以下单
                    trade_index, is_default = cls.__TradeBuyQueue.get_traded_index(code)
                    if trade_index is None:
                        trade_index = 0
                    can_place_order, msg = buy_strategy_util.is_near_by_trade_index(code, trade_index)
                    if not can_place_order:
                        try:
                            # 不能下单,判断小群撤是否可以下
                            if buy_strategy_util.is_has_small_batch_cancel(code, trade_index,
                                                                           order_begin_pos.buy_single_index):
                                # 判断撤单比例是否足够
                                if not buy_strategy_util.is_cancel_rate_reieved(code, 0.69, trade_index,
                                                                                order_begin_pos.buy_single_index):
                                    return False, True, f"板上放量距离远({not_limit_up_trade_time_with_ms}),有小群撤, 整体撤单比例不足({trade_index}-{order_begin_pos.buy_single_index})"
                            else:
                                return False, True, f"板上放量距离远({not_limit_up_trade_time_with_ms}),没有小群撤({trade_index}-{order_begin_pos.buy_single_index})"
                        except Exception as e:
                            l2_log.info(code, logger_l2_error, f"板上放量({not_limit_up_trade_time_with_ms})不足异常:{str(e)}")
                            return False, True, f"板上放量计算异常"
                    # -------是否距离成交进度位太远--------
                    buy1_money = code_price_manager.Buy1PriceManager().get_latest_buy1_money(code)
                    buy1_price = code_price_manager.Buy1PriceManager().get_buy1_price(code)
                    if buy1_price and abs(limit_up_price - buy1_price) > 0.0001:
                        # 买1未涨停
                        buy1_money = 0
                    if not buy1_money:
                        buy1_money = 1
                    deal_rate = round(total_deal_money / buy1_money, 2)
                    if deal_rate < 0.5:
                        # 判断成交进度到当前数据的笔数,如果少于10笔且还有未成交的大单(>=299)就可以下单
                        trade_index, is_default = cls.__TradeBuyQueue.get_traded_index(code)
                        if trade_index is None:
                            trade_index = 0
                        can_place_order, msg = buy_strategy_util.is_near_by_trade_index(code, trade_index)
                        if not can_place_order:
                            try:
                                # 不能下单,判断小群撤是否可以下
                                if buy_strategy_util.is_has_small_batch_cancel(code, trade_index,
                                                                               order_begin_pos.buy_single_index):
                                    # 判断撤单比例是否足够
                                    if not buy_strategy_util.is_cancel_rate_reieved(code, 0.69, trade_index,
                                                                                    order_begin_pos.buy_single_index):
                                        return False, True, f"板上放量不足,有小群撤, 整体撤单比例不足({trade_index}-{order_begin_pos.buy_single_index})"
                                else:
                                    return False, True, f"板上放量不足,且没有小群撤({trade_index}-{order_begin_pos.buy_single_index})"
                            except Exception as e:
                                l2_log.info(code, logger_l2_error, "板上放量不足异常:{}", str(e))
                                return False, True, f"板上放量不足"
            # 上证下单需要有成交大单(包含主动买与被动买)或者挂买的大单
                    if buy_strategy_util.is_far_away_from_trade_index(code, trade_index, buy1_money):
                        return False, True, f"距离成交进度位太远:成交进度-{trade_index} 买1-{buy1_money}"
            # ------------------上证下单需要有成交大单(包含主动买与被动买)或者挂买的大单-----------------
            if tool.is_sh_code(code):
                deal_big_order_count = BigOrderDealManager().get_total_buy_count(code)
                if deal_big_order_count < 1:
@@ -983,7 +997,7 @@
                    if left_count < 1:
                        return False, False, f"没有已挂或者成交的大单"
            place_order_count = trade_data_manager.PlaceOrderCountManager().get_place_order_count(code)
            # 第一和第二次下单都必须要有至少一笔未成交的大单
            # ------------------第一和第二次下单都必须要有至少一笔未成交的大单--------------------------
            # 计算大单
            total_datas = local_today_datas.get(code)
            if place_order_count < 2:
@@ -997,47 +1011,16 @@
                if left_count < 1:
                    return False, False, f"第{place_order_count + 1}下单无待成交的大单"
            # 执行位那一戳数据要小于20条数据
            THRESHOLD_BUY_COUNT = 20
            buy_count = 0
            min_num = int(5000 / limit_up_price)
            # -------判断是否是量化下单,如果是就不跟到下单--------
            # 重要:量化下单会增加下单次数,板块下单中有下单次数的使用,所以板块需要在量化判断之前
            # 只有板块满足下单之后才能判断其它条件
            range_indexes = cls.__processing_data_indexes.get(code)
            trade_index, is_default = transaction_progress.TradeBuyQueue().get_traded_index(code)
            if trade_index is None:
                trade_index = 0
            if range_indexes:
                # 获取成交进度位
                for i in range(range_indexes[0], range_indexes[1] + 1):
                    val = total_datas[i]["val"]
                    if not L2DataUtil.is_limit_up_price_buy(val):
                        continue
                    if val["num"] < min_num:
                        continue
                    buy_count += 1
                    if buy_count > THRESHOLD_BUY_COUNT:
                        break
            if buy_count > THRESHOLD_BUY_COUNT:
                # 判断是否为量化
                time_as_ms = tool.trade_time_sub_with_ms(
                    L2DataUtil.get_time_with_ms(total_datas[range_indexes[1]]["val"]),
                    L2DataUtil.get_time_with_ms(total_datas[range_indexes[0]]["val"]))
                if time_as_ms <= 10 if tool.is_sz_code(code) else 100:
                    # 深证10ms内,上证100ms内就判定为量化
                    HuaXinSellOrderStatisticManager.clear_latest_deal_volume(code)
                    cls.__next_buy_time_dict[code] = t.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 False, True, f"执行位批次数据量({buy_count})大于{THRESHOLD_BUY_COUNT}  {range_indexes[0]}-{range_indexes[1]}"
            # 暂时注释想买单功能
        if not cls.__WantBuyCodesManager.is_in_cache(code):
            # if cls.__TradeTargetCodeModeManager.get_mode_cache() == TradeTargetCodeModeManager.MODE_ONLY_BUY_WANT_CODES:
            #     return False, True, f"只买想买单中的代码"
            return cls.can_buy_first_new(code, limit_up_price)
        else:
            return True, False, "在想买单中"
                is_quantization_result = buy_strategy_util.is_quantization(code, range_indexes[0], range_indexes[1])
                if is_quantization_result[0]:
                    cls.__next_buy_time_dict[code] = is_quantization_result[1]
                    return False, True, is_quantization_result[2]
        return True, False, "满足下单条件"
    # 获取可以买的板块
    @classmethod
@@ -1348,6 +1331,10 @@
                            is_first_code,
                            new_add=True):
        # 中断当前批次买入数据处理
        if cls.__break_current_batch_data_for_buy_dict.get(code):
            return
        # 判断下次买入时间是否正确
        if code in cls.__next_buy_time_dict and t.time() < cls.__next_buy_time_dict[code]:
            return
l2/l2_transaction_data_processor.py
@@ -84,8 +84,7 @@
            limit_up_price = round(float(limit_up_price), 2)
        # 设置成交价
        try:
            current_price_process_manager.set_trade_price(code, datas[-1][1], l2_huaxin_util.convert_time(datas[-1][3]),
                                                          limit_up_price)
            current_price_process_manager.set_trade_price(code, datas[-1][1])
        except:
            pass
        total_datas = l2_data_util.local_today_datas.get(code)
@@ -101,6 +100,18 @@
            big_sell_order_info = None
            try:
                # 统计上板时间
                try:
                    for d in datas:
                        if d[6] > d[7]:
                            # 主动买
                            if d[1] == limit_up_price:
                                # 涨停
                                current_price_process_manager.set_latest_not_limit_up_time(code,
                                                                                           l2_huaxin_util.convert_time(
                                                                                               d[3], with_ms=True))
                except:
                    pass
                # 统计卖单
                big_sell_order_info = HuaXinSellOrderStatisticManager.add_transaction_datas(code, datas, limit_up_price)
@@ -120,7 +131,7 @@
                    # 判断时间是否与本地时间相差5s以上
                    if tool.trade_time_sub(tool.get_now_time_str(), l2_huaxin_util.convert_time(datas[-1][3])) > 10:
                        now_seconds = int(tool.get_now_time_str().replace(":", ""))
                        if now_seconds < int("093200"): #or int("130000") <= now_seconds < int("130200"):
                        if now_seconds < int("093200"):  # or int("130000") <= now_seconds < int("130200"):
                            need_cancel, cancel_msg = True, f"成交时间与本地时间相差10S以上,{l2_huaxin_util.convert_time(datas[-1][3])}"
                    if need_cancel:
                        L2TradeDataProcessor.cancel_buy(code, cancel_msg)
test/test.py
@@ -21,4 +21,4 @@
if __name__ == "__main__":
    global_data_loader.load_zyltgb_volume_from_db()
    print(1e7)
trade/current_price_process_manager.py
@@ -46,7 +46,7 @@
                rate = round((price - pricePre) * 100 / pricePre, 2)
                if tool.is_ge_code(code):
                    # 创业板的涨幅需要打折
                    rate = rate/2
                    rate = rate / 2
                if rate >= 0 and not trade_manager.ForbiddenBuyCodeByScoreManager().is_in_cache(code):
                    # 暂存涨幅为正的代码
                    _code_list.append((rate, code, 1 if is_want_buy else 0))
@@ -165,12 +165,19 @@
# 设置成交价
def set_trade_price(code, price, time_str, limit_up_price):
def set_trade_price(code, price):
    __trade_price_dict[code] = price
    # 需要记录最近一次非涨停价成交的时间
    if limit_up_price and abs(limit_up_price - price) > 0.001:
        # 非涨停价成交
        __trade_price_not_limit_up_info_dict[code] = (price, time_str)
def set_latest_not_limit_up_time(code, time_str_with_ms):
    """
    记录最近的一次上板时间(最近的一笔主动买就是上板时间)
    @param code:
    @param time_str:
    @return:
    """
    __trade_price_not_limit_up_info_dict[code] = time_str_with_ms
# 获取成交价
@@ -178,10 +185,10 @@
    return __trade_price_dict.get(code)
def get_trade_not_limit_up_info(code):
def get_trade_not_limit_up_time_with_ms(code):
    """
    获取最近的非涨停价成交的信息
    获取最近的非板上成交的时间
    @param code:
    @return:(价格,时间)
    @return:(价格, 时间)
    """
    return __trade_price_not_limit_up_info_dict.get(code)
utils/buy_strategy_util.py
@@ -1,9 +1,15 @@
"""
买入策略帮助类
"""
import time
from code_attribute import gpcode_manager
from l2 import l2_data_util, l2_data_source_util
from utils import tool
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 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):
@@ -49,6 +55,14 @@
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))
@@ -80,6 +94,43 @@
        return False
    if round(cancel_count / buy_count, 2) > threshhold_rate:
        return True
    return False
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
@@ -117,3 +168,113 @@
    if total_count > 10 or total_big_count < 1:
        return False, f"未成交数量-{total_count},大单数量-{total_big_count}"
    return True, ""
def is_quantization(code, start_index, end_index):
    """
    是否是量化单
    @param code:
    @param satrt_index:
    @param end_index:
    @return:(是否是量化, 下次可以下单时间)
    """
    THRESHOLD_BUY_COUNT = 20
    if end_index - start_index + 1 < THRESHOLD_BUY_COUNT:
        # 总数小于阈值
        return False, None
    total_datas = l2_data_util.local_today_datas.get(code)
    limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
    buy_count = 0
    min_num = int(5000 / limit_up_price)
    trade_index, is_default = transaction_progress.TradeBuyQueue().get_traded_index(code)
    if trade_index is None:
        trade_index = 0
    # 获取成交进度位
    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
        buy_count += 1
        if buy_count > THRESHOLD_BUY_COUNT:
            break
    if buy_count > THRESHOLD_BUY_COUNT:
        # 判断是否为量化
        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:
            # 深证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"执行位批次数据量({buy_count})大于{THRESHOLD_BUY_COUNT}  {start_index}-{end_index}"
        return False, None
    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]