From 892b50e242e3c59a738b92dfdfee1bf1ff8932f2 Mon Sep 17 00:00:00 2001
From: Administrator <admin@example.com>
Date: 星期五, 21 十月 2022 16:59:58 +0800
Subject: [PATCH] 新策略修改

---
 l2_data_manager.py |  395 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 366 insertions(+), 29 deletions(-)

diff --git a/l2_data_manager.py b/l2_data_manager.py
index c19499f..a5eca4d 100644
--- a/l2_data_manager.py
+++ b/l2_data_manager.py
@@ -73,9 +73,9 @@
         _key = "buy_compute_index_info-{}".format(code)
         _data_json = redis.get(_key)
         if _data_json is None:
-            return None, None, None, 0
+            return None, None, None, 0, 0
         _data = json.loads(_data_json)
-        return _data[0], _data[1], _data[2], _data[3]
+        return _data[0], _data[1], _data[2], _data[3], _data[4]
 
     # 璁剧疆涔板叆鐐圭殑鍊�
     # buy_single_index 涔板叆淇″彿浣�
@@ -83,16 +83,16 @@
     # compute_index 璁$畻浣嶇疆
     # nums 绱绾拱棰�
     @staticmethod
-    def set_buy_compute_start_data(code, buy_single_index, buy_exec_index, compute_index, nums):
+    def set_buy_compute_start_data(code, buy_single_index, buy_exec_index, compute_index, nums, count):
         redis = TradePointManager.__get_redis()
         expire = tool.get_expire()
         _key = "buy_compute_index_info-{}".format(code)
         if buy_single_index is not None:
-            redis.setex(_key, expire, json.dumps((buy_single_index, buy_exec_index, compute_index, nums)))
+            redis.setex(_key, expire, json.dumps((buy_single_index, buy_exec_index, compute_index, nums, count)))
         else:
-            _buy_single_index, _buy_exec_index, _compute_index, _nums = TradePointManager.get_buy_compute_start_data(
+            _buy_single_index, _buy_exec_index, _compute_index, _nums, _count = TradePointManager.get_buy_compute_start_data(
                 code)
-            redis.setex(_key, expire, json.dumps((_buy_single_index, buy_exec_index, compute_index, nums)))
+            redis.setex(_key, expire, json.dumps((_buy_single_index, buy_exec_index, compute_index, nums, count)))
 
     # 鑾峰彇鎾や拱鍏ュ紑濮嬭绠楃殑淇℃伅
     # 杩斿洖鏁版嵁鐨勫唴瀹逛负锛氭挙閿�鐐圭储寮� 鎾や拱绾拱棰� 璁$畻鐨勬暟鎹储寮�
@@ -265,6 +265,16 @@
         saveL2Data(code, add_datas)
 
 
+# 娓呴櫎l2鏁版嵁
+def clear_l2_data(code):
+    redis_l2 = redis_manager.RedisManager(1).getRedis()
+    keys = redis_l2.keys("l2-{}-*".format(code))
+    for k in keys:
+        redis_l2.delete(k)
+
+    redis_l2.delete("l2-data-latest-{}".format(code))
+
+
 class L2DataUtil:
     @classmethod
     def is_same_time(cls, time1, time2):
@@ -363,10 +373,11 @@
                 else:
                     limitPrice = 0
                 item["limitPrice"] = "{}".format(limitPrice)
-            # 涓嶉渶瑕侀潪娑ㄥ仠鏁版嵁/闈炶穼鍋滄暟鎹�
-            if int(item["limitPrice"]) == 0:
-                continue
             operateType = item["operateType"]
+            # 涓嶉渶瑕侀潪娑ㄥ仠涔颁笌涔版挙
+            if int(item["limitPrice"]) != 1 and (int(operateType) == 0 or int(operateType) == 1):
+                continue
+
             cancelTime = item["cancelTime"]
             cancelTimeUnit = item["cancelTimeUnit"]
             key = "{}-{}-{}-{}-{}-{}-{}-{}".format(code, operateType, time, num, price, limitPrice, cancelTime,
@@ -380,6 +391,8 @@
                 dataIndexs.setdefault(key, len(datas) - 1)
         l2_data_util.save_big_data(code, same_time_num, data)
         return datas
+
+
 
     @classmethod
     def get_time_as_second(cls, time_str):
@@ -406,6 +419,20 @@
             return False
         return True
 
+    @classmethod
+    def is_limit_up_price_sell(cls, val):
+        if int(val["limitPrice"]) != 1:
+            return False
+
+        if int(val["operateType"]) != 2:
+            return False
+
+        price = float(val["price"])
+        num = int(val["num"])
+        if price * num * 100 < 50 * 10000:
+            return False
+        return True
+
     # 鏄惁娑ㄥ仠涔版挙
     @classmethod
     def is_limit_up_price_buy_cancel(cls, val):
@@ -420,6 +447,20 @@
         if price * num * 100 < 50 * 10000:
             return False
         return True
+
+    # 鏄惁鍗栨挙
+    @classmethod
+    def is_sell_cancel(cls, val):
+        if int(val["operateType"]) == 3:
+            return True
+        return False
+
+    # 鏄惁涓哄崠
+    @classmethod
+    def is_sell(cls, val):
+        if int(val["operateType"]) == 2:
+            return True
+        return False
 
 
 # L2浜ゆ槗鏁版嵁澶勭悊鍣�
@@ -484,17 +525,17 @@
                     latest_time = add_datas[len(add_datas) - 1]["val"]["time"]
                     # 鏃堕棿宸笉鑳藉お澶ф墠鑳藉鐞�
                     # TODO 鏆傛椂鍏抽棴澶勭悊
-                    if L2DataUtil.is_same_time(now_time_str, latest_time):
-                        # 鍒ゆ柇鏄惁宸茬粡鎸傚崟
-                        state = trade_manager.get_trade_state(code)
-                        start_index = len(total_datas) - len(add_datas)
-                        end_index = len(total_datas) - 1
-                        if state == trade_manager.TRADE_STATE_BUY_DELEGATED or state == trade_manager.TRADE_STATE_BUY_PLACE_ORDER:
-                            # 宸叉寕鍗�
-                            cls.__process_order(code, start_index, end_index, capture_timestamp)
-                        else:
-                            # 鏈寕鍗�
-                            cls.__process_not_order(code, start_index, end_index, capture_timestamp)
+                    # if L2DataUtil.is_same_time(now_time_str, latest_time):
+                    #     # 鍒ゆ柇鏄惁宸茬粡鎸傚崟
+                    #     state = trade_manager.get_trade_state(code)
+                    #     start_index = len(total_datas) - len(add_datas)
+                    #     end_index = len(total_datas) - 1
+                    #     if state == trade_manager.TRADE_STATE_BUY_DELEGATED or state == trade_manager.TRADE_STATE_BUY_PLACE_ORDER:
+                    #         # 宸叉寕鍗�
+                    #         cls.__process_order(code, start_index, end_index, capture_timestamp)
+                    #     else:
+                    #         # 鏈寕鍗�
+                    #         cls.__process_not_order(code, start_index, end_index, capture_timestamp)
                     logger_l2_process.info("code:{} 澶勭悊鏁版嵁鑼冨洿: {}-{} 澶勭悊鏃堕棿:{}", code, add_datas[0]["index"],
                                            add_datas[-1]["index"], round(t.time() * 1000) - __start_time)
                 # 淇濆瓨鏁版嵁
@@ -722,6 +763,8 @@
         except Exception as e:
             cls.debug(code, "鎵ц涔板叆寮傚父:{}", str(e))
             pass
+        finally:
+            cls.debug(code, "m鍊煎奖鍝嶅洜瀛愶細", l2_trade_factor.L2TradeFactorUtil.factors_to_string(code))
 
     # 鏄惁鍙互涔�
     @classmethod
@@ -774,10 +817,19 @@
         # 鍒犻櫎澶х兢鎾や簨浠剁殑澶у崟
         L2BetchCancelBigNumProcessor.del_recod(code)
         L2ContinueLimitUpCountManager.del_data(code)
+
         if code in cls.unreal_buy_dict:
             cls.unreal_buy_dict.pop(code)
+            # 鍙栨秷涔板叆鏍囪瘑
+            TradePointManager.delete_buy_point(code)
+            TradePointManager.delete_buy_cancel_point(code)
+            TradePointManager.delete_compute_info_for_cancel_buy(code)
+            TradePointManager.delete_count_info_for_cancel_buy(code)
+            # 鍒犻櫎澶х兢鎾や簨浠剁殑澶у崟
+            L2BetchCancelBigNumProcessor.del_recod(code)
         else:
             cls.__cancel_buy(code)
+
         L2BigNumProcessor.del_big_num_pos(code)
 
     @classmethod
@@ -905,7 +957,7 @@
                 count += datas[i]["re"]
                 if count >= continue_count:
                     return True, start
-            else:
+            elif not L2DataUtil.is_limit_up_price_sell(_val):
                 last_index = None
                 count = 0
                 start = None
@@ -931,7 +983,7 @@
                     start = i
                     start_time = L2DataUtil.get_time_as_second(_val["time"])
                 count += datas[i]["re"]
-            else:
+            elif not L2DataUtil.is_limit_up_price_sell(_val):
                 if count >= continue_count:
                     return start, i - 1
                 start = -1
@@ -967,7 +1019,7 @@
                     start = i
                     start_time = L2DataUtil.get_time_as_second(_val["time"])
                 count += int(datas[i]["re"])
-            else:
+            elif not L2DataUtil.is_limit_up_price_sell(_val):
                 if count >= continue_count:
                     return start, i - 1
                 start = -1
@@ -1323,7 +1375,7 @@
 
     @classmethod
     def test_can_order(cls):
-        code = "002393"
+        code = "000948"
 
         global_util.load_industry()
         limit_up_time_manager.load_limit_up_time()
@@ -1618,8 +1670,9 @@
                 if need_cancel:
                     # 闇�瑕佹挙鍗�
                     # 鎾ゅ崟
-                    cls.__cancel_buy(code, max_num_data["index"])
-                    L2TradeDataProcessor.cancel_debug(code, "璺熻釜鍒板ぇ鍗曟棤鎾や拱淇″彿-{}锛屾柊璺熻釜鐨勫ぇ鍗曢渶瑕佹挙涔�-{}", index, max_num_data["index"])
+                    cls.__cancel_buy(code, max_num_data["index"] if cancel_data is None else cancel_data)
+                    L2TradeDataProcessor.cancel_debug(code, "鍘熸潵璺熻釜鍒板ぇ鍗曟棤鎾や拱淇″彿-{}锛屾柊璺熻釜鐨勫ぇ鍗曢渶瑕佹挙涔�-{}", index,
+                                                      max_num_data["index"])
                     return True, cancel_data
                 else:
                     # 鏃犻渶鎾ゅ崟
@@ -1695,8 +1748,8 @@
             if i <= latest_buy_index:
                 total_count += total_datas[i]["re"]
         L2TradeDataProcessor.debug(code, "澶х兢鎾ゅぇ鍗曟暟閲忥細{}/{}", count, total_count)
-        # 澶у崟灏忎簬5绗旀棤鑴戞挙
-        if total_count <= 5:
+        # 澶у崟灏忎簬5绗旀棤鑴戞挙锛屽悗淇敼涓烘棤澶у崟鏃犺剳鎾�
+        if total_count <= 0:
             return True
 
         # 澶у崟鎾ゅ崟绗旀暟澶т簬鎬诲ぇ鍗曠瑪鏁扮殑1/5灏辨挙鍗�
@@ -1788,6 +1841,287 @@
                     index_set.add(d[1])
                     big_nums_info_new.append(d)
             cls.__save_recod(code, max_big_num_info, big_nums_info_new)
+
+
+# 鍗栬窡韪�
+class L2SellProcessor:
+    @classmethod
+    def __get_recod(cls, code):
+        redis = _redisManager.getRedis()
+        _val = redis.get("sell_num-{}".format(code))
+        if _val is None:
+            return None, None
+        else:
+            datas = json.loads(_val)
+            return datas[0], datas[1]
+
+    @classmethod
+    def del_recod(cls, code):
+        redis = _redisManager.getRedis()
+        key = "sell_num-{}".format(code)
+        redis.delete(key)
+
+    @classmethod
+    def __save_recod(cls, code, process_index, count):
+        redis = _redisManager.getRedis()
+        key = "sell_num-{}".format(code)
+        redis.setex(key, tool.get_expire(), json.dumps((process_index, count)))
+
+    # 鏆傛椂寮冪敤
+    @classmethod
+    def need_cancel(cls, code, start_index, end_index):
+        # 鏄惁闇�瑕佹挙鍗�
+        process_index, count = cls.__get_recod(code)
+        if process_index is None:
+            # 鏃犲崠鐨勪俊鎭�
+            return False
+        if count is None:
+            count = 0
+        limit_up_price = gpcode_manager.get_limit_up_price(code)
+        if limit_up_price is None:
+            return False
+        if float(limit_up_price) * count * 100 >= l2_trade_factor.L2TradeFactorUtil.get_base_safe_val(
+                global_util.zyltgb_map[code]):
+            return True
+        return False
+
+    @classmethod
+    def process(cls, code, start_index, end_index):
+        # 澶勭悊澶у崟
+        # 鑾峰彇澶у崟鍒楄〃,澶у崟鏍煎紡涓�:((num,index,re),[(num,index,re),(num,index,re)])
+        total_datas = local_today_datas[code]
+        process_index, count = cls.__get_recod(code)
+        # 瀵绘壘鏈�澶у��
+        for index in range(start_index, end_index + 1):
+            # 鍙鐞嗘定鍋滃崠
+            if not L2DataUtil.is_limit_up_price_sell(
+                    total_datas[index]["val"]):
+                continue
+            # 涓嶅鐞嗗巻鍙叉暟鎹�
+            if process_index is not None and process_index >= index:
+                continue
+            if count is None:
+                count = 0
+            count += int(total_datas[index]["val"]["num"])
+        if process_index is None:
+            process_index = end_index
+        cls.__save_recod(code, process_index, count)
+
+
+# 娑ㄥ仠灏佸崟棰濈粺璁�
+class L2LimitUpMoneyStatisticUtil:
+    _redisManager = redis_manager.RedisManager(1)
+
+    @classmethod
+    def __get_redis(cls):
+        return cls._redisManager.getRedis()
+
+    # 璁剧疆l2鐨勬瘡涓�绉掓定鍋滃皝鍗曢鏁版嵁
+    @classmethod
+    def __set_l2_second_money_record(cls, code, time, num, from_index, to_index):
+        old_num, old_from, old_to = cls.__get_l2_second_money_record(code, time)
+        if old_num is None:
+            old_num = num
+            old_from = from_index
+            old_to = to_index
+        else:
+            old_num += num
+            old_to = to_index
+
+        key = "l2_limit_up_second_money-{}-{}".format(code, time.replace(":", ""))
+
+        cls.__get_redis().setex(key, tool.get_expire(), json.dumps((old_num, old_from, old_to)))
+
+    @classmethod
+    def __get_l2_second_money_record(cls, code, time):
+        key = "l2_limit_up_second_money-{}-{}".format(code, time.replace(":", ""))
+        val = cls.__get_redis().get(key)
+        return cls.__format_second_money_record_val(val)
+
+    @classmethod
+    def __format_second_money_record_val(cls, val):
+        if val is None:
+            return None, None, None
+        val = json.loads(val)
+        return val[0], val[1], val[2]
+
+    @classmethod
+    def __get_l2_second_money_record_keys(cls, code, time_regex):
+        key = "l2_limit_up_second_money-{}-{}".format(code, time_regex)
+        keys = cls.__get_redis().keys(key)
+        return keys
+
+    # 璁剧疆l2鏈�鏂扮殑灏佸崟棰濇暟鎹�
+    @classmethod
+    def __set_l2_latest_money_record(cls, code, index, num):
+        key = "l2_limit_up_money-{}".format(code)
+        cls.__get_redis().setex(key, tool.get_expire(), json.dumps((num, index)))
+
+    # 杩斿洖鏁伴噺,绱㈠紩
+    @classmethod
+    def __get_l2_latest_money_record(cls, code):
+        key = "l2_limit_up_money-{}".format(code)
+        result = cls.__get_redis().get(key)
+        if result:
+            result = json.loads(result)
+            return result[0], result[1]
+        else:
+            return 0, -1
+
+    # 鐭鏁版嵁
+    # 鐭鏂规硶涓哄彇鐭鏃堕棿涓や晶鐨勭鍒嗗竷鏁版嵁锛岀敤浜庣‘瀹氳绠楃粨鏉熷潗鏍�
+    @classmethod
+    def verify_num(cls, code, num, time_str):
+        time_ = time_str.replace(":", "")
+        key = None
+        for i in range(4, -2, -2):
+            # 鑾峰彇鏈�(鍒嗛挓/灏忔椂/澶�)鍐呯鍒嗗竷鏁版嵁
+            time_regex = "{}*".format(time_[:i])
+            keys_ = cls.__get_l2_second_money_record_keys(code, time_regex)
+            if keys_ and len(keys_) > 1:
+                # 闇�瑕佹帓搴�
+                keys = []
+                for k in keys_:
+                    keys.append(k)
+                keys.sort(key=lambda tup: int(tup.split("-")[-1]))
+                # 鏈�2涓厓绱�
+                for index in range(0, len(keys) - 1):
+                    time_1 = keys[index].split("-")[-1]
+                    time_2 = keys[index + 1].split("-")[-1]
+                    if int(time_1) <= int(time_) <= int(time_2):
+                        # 鍦ㄦ鏃堕棿鑼冨洿鍐�
+                        if time_ == time_2:
+                            key = keys[index + 1]
+                        else:
+                            key = keys[index]
+                        break
+            if key:
+                val = cls.__get_redis().get(key)
+                old_num, old_from, old_to = cls.__format_second_money_record_val(val)
+                end_index = old_to
+                # 淇濆瓨鏈�杩戠殑鏁版嵁
+                cls.__set_l2_latest_money_record(code, end_index, num)
+                break
+
+    # 璁$畻閲忥紝鐢ㄤ簬娑ㄥ仠灏佸崟閲忕殑璁$畻
+    @classmethod
+    def __compute_num(cls, code, data, buy_single_data):
+        if L2DataUtil.is_limit_up_price_buy_cancel(data["val"]) or L2DataUtil.is_sell(data["val"]):
+            # 娑ㄥ仠涔版挙涓庡崠
+            return 0 - int(data["val"]["num"]) * data["re"]
+        else:
+            # 鍗栨挙
+            if L2DataUtil.is_sell_cancel(data["val"]):
+                # 鍗栨挙鐨勪拱鏁版嵁鏄惁鍦ㄤ拱鍏ヤ俊鍙蜂箣鍓嶏紝濡傛灉鍦ㄤ箣鍓嶅氨涓嶈绠楋紝涓嶅湪涔嬪墠灏辫绠�
+                if l2_data_util.is_sell_index_before_target(data, buy_single_data,
+                                                            local_today_num_operate_map.get(code)):
+                    return 0
+
+            return int(data["val"]["num"]) * data["re"]
+
+    @classmethod
+    def clear(cls, code):
+        key = "l2_limit_up_money-{}".format(code)
+        cls.__get_redis().delete(key)
+
+    # 杩斿洖鍙栨秷鐨勬爣蹇楁暟鎹�
+    # with_cancel 鏄惁闇�瑕佸垽鏂槸鍚︽挙閿�
+    @classmethod
+    def process_data(cls, code, start_index, end_index, buy_single_begin_index, with_cancel=True):
+        start_time = round(t.time() * 1000)
+        total_datas = local_today_datas[code]
+        time_dict_num = {}
+        # 璁板綍璁$畻鐨勫潗鏍�
+        time_dict_num_index = {}
+        num_dict = {}
+        # 缁熻鏃堕棿鍒嗗竷
+        time_dict = {}
+        for i in range(start_index, end_index + 1):
+            data = total_datas[i]
+            val = data["val"]
+            time_ = val["time"]
+            if time_ not in time_dict:
+                time_dict[time_] = i
+
+        for i in range(start_index, end_index + 1):
+            data = total_datas[i]
+            val = data["val"]
+            time_ = val["time"]
+            if time_ not in time_dict_num:
+                time_dict_num[time_] = 0
+                time_dict_num_index[time_] = {"s": i, "e": i}
+            time_dict_num_index[time_]["e"] = i
+            num = cls.__compute_num(code, data, total_datas[buy_single_begin_index])
+            num_dict[i] = num
+            time_dict_num[time_] = time_dict_num[time_] + num
+        for t_ in time_dict_num:
+            cls.__set_l2_second_money_record(code, t_, time_dict_num[t_], time_dict_num_index[t_]["s"],
+                                             time_dict_num_index[t_]["e"])
+
+        print("淇濆瓨娑ㄥ仠灏佸崟棰濇椂闂达細", round(t.time() * 1000) - start_time)
+
+        # 绱鏈�鏂扮殑閲戦
+        total_num, index = cls.__get_l2_latest_money_record(code)
+        if index == -1:
+            # 娌℃湁鑾峰彇鍒版渶鏂扮殑鐭灏佸崟棰濓紝闇�瑕佷粠涔板叆淇″彿寮�濮嬬偣璁$畻
+            index = buy_single_begin_index - 1
+            total_num = 0
+        # TODO 寰呬紭鍖栬绠�
+        cancel_index = None
+        cancel_msg = None
+        # 寰呰绠楅噺
+        limit_up_price = gpcode_manager.get_limit_up_price(code)
+        min_volumn = round(10000000 / (limit_up_price * 100))
+        # 涓嶅悓鏃堕棿鐨勬暟鎹紑濮嬪潗鏍�
+        time_start_index_dict = {}
+        # 鏁版嵁鏃堕棿鍒嗗竷
+        time_list = []
+        # 鍒板綋鍓嶆椂闂寸疮绉殑涔�1閲�
+        time_total_num_dict = {}
+        for i in range(index + 1, end_index + 1):
+            data = total_datas[i]
+            time_ = data["val"]["time"]
+            if time_ not in time_start_index_dict:
+                # 璁板綍姣忎竴绉掔殑寮�濮嬩綅缃�
+                time_start_index_dict[time_] = i
+                # 璁板綍鏃堕棿鍒嗗竷
+                time_list.append(time_)
+                # 涓婁竴娈垫椂闂寸殑鎬绘暟
+                time_total_num_dict[time_] = total_num
+
+            val = num_dict.get(i)
+            if val is None:
+                val = cls.__compute_num(code, data, total_datas[buy_single_begin_index])
+            total_num += val
+            # 濡傛灉鏄噺灏忛」锛屼笖鍦ㄥ鐞嗘暟鎹殑鑼冨洿鍐咃紝灏遍渶瑕佸垽鏂槸鍚﹁鎾ゅ崟浜�
+            if val < 0 and start_index <= i <= end_index:
+                # 绱灏佸崟閲戦灏忎簬1000涓�
+                if total_num < min_volumn:
+                    cancel_index = i
+                    cancel_msg = "灏佸崟閲戦灏忎簬1000涓�"
+                    break
+                # 鐩搁偦2s鍐呯殑鏁版嵁鍑忓皬50%
+                # 涓�1s鐨勬�绘暟
+                last_second_total_volumn = time_total_num_dict.get(time_list[-1])
+                if last_second_total_volumn > 0 and (
+                        last_second_total_volumn - total_num) / last_second_total_volumn >= 0.5:
+                    # 鐩搁偦2s鍐呯殑鏁版嵁鍑忓皬50%
+                    cancel_index = i
+                    cancel_msg = "鐩搁偦2s({})鍐呯殑灏佸崟閲忓噺灏�50%({}->{})".format(time_, last_second_total_volumn,
+                                                                     total_num)
+                    break
+        if not with_cancel:
+            cancel_index = None
+
+        print("灏佸崟棰濊绠楁椂闂达細", round(t.time() * 1000) - start_time)
+        process_end_index = end_index
+        if cancel_index:
+            process_end_index = cancel_index
+        # 淇濆瓨鏈�鏂扮疮璁¢噾棰�
+        # cls.__set_l2_latest_money_record(code, process_end_index, total_num)
+        if cancel_index:
+            return total_datas[cancel_index], cancel_msg
+        return None, None
 
 
 def __get_time_second(time_str):
@@ -2035,4 +2369,7 @@
 
 
 if __name__ == "__main__":
-    L2TradeDataProcessor.test_can_order()
+    # 澶勭悊鏁版嵁
+    code = "002898"
+    load_l2_data(code)
+    L2LimitUpMoneyStatisticUtil.verify_num(code, 70582, "09:42:00")

--
Gitblit v1.8.0