From ad3cc1a24c4b413bae3069cc6d1c2a1923540ce3 Mon Sep 17 00:00:00 2001
From: Administrator <admin@example.com>
Date: 星期五, 25 七月 2025 15:51:48 +0800
Subject: [PATCH] 开盘啦TCP请求/委托数据持久化异步处理

---
 utils/buy_strategy_util.py |  258 +++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 225 insertions(+), 33 deletions(-)

diff --git a/utils/buy_strategy_util.py b/utils/buy_strategy_util.py
index 10eeaf4..7d0960d 100644
--- a/utils/buy_strategy_util.py
+++ b/utils/buy_strategy_util.py
@@ -1,9 +1,17 @@
 """
 涔板叆绛栫暐甯姪绫�
 """
-from code_attribute import gpcode_manager
-from l2 import l2_data_util, l2_data_source_util
-from utils import tool
+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):
@@ -22,7 +30,7 @@
     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, -1):
+    for i in range(end_index - 1, start_index, -1):
         data = total_datas[i]
         val = data["val"]
         if val["num"] < min_num:
@@ -37,7 +45,7 @@
                         break
             continue
         # 涓庡綋鍓嶆椂闂寸浉宸�3s鐨勭粨鏉�
-        if tool.trade_time_sub_with_ms(end_time_with_ms, l2_data_util.L2DataUtil.get_time_with_ms(val)) > 3000:
+        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
@@ -49,6 +57,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))
@@ -77,9 +93,46 @@
         if buy_index and start_index <= buy_index:
             cancel_count += 1
     if buy_count == 0:
-        return False
+        return False, "涔板叆鏁伴噺涓�0"
     if round(cancel_count / buy_count, 2) > threshhold_rate:
-        return True
+        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
 
 
@@ -90,30 +143,169 @@
     @param trade_index:
     @return:
     """
-    total_data = l2_data_util.local_today_datas.get(code)
-    total_count = 0
-    total_big_count = 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
+    # 鑾峰彇浠婃棩鎴愪氦閲忎笌鍙傝�冮噺
+    # 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)
 
-        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_count += 1
-            if money > 29900:
-                total_big_count += 1
-            if total_count > 10:
-                break
-    if total_count > 10 or total_big_count < 1:
-        return False, f"鏈垚浜ゆ暟閲�-{total_count}锛屽ぇ鍗曟暟閲�-{total_big_count}"
-    return True, ""
+        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]

--
Gitblit v1.8.0