Administrator
2023-07-06 80626deca1a6f74bab126cdda8e1a3a71508e4d4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
"""
代码行业关键词管理
"""
 
# 涨停代码关键词板块管理
import json
 
import constant
from utils import global_util, tool
from logs_ import log
from db import redis_manager
 
from logs_.log import logger_kpl_limit_up, logger_kpl_block_can_buy
from third_data.kpl_util import KPLPlatManager
from trade import trade_manager
 
 
# 开盘啦禁止交易板块管理
class KPLPlateForbiddenManager:
    __redisManager = redis_manager.RedisManager(3)
 
    def __get_redis(self):
        return self.__redisManager.getRedis()
 
    def save_plate(self, plate):
        self.__get_redis().sadd("kpl_forbidden_plates", plate)
        self.__get_redis().expire("kpl_forbidden_plates", tool.get_expire())
 
    def list_all(self):
        return self.__get_redis().smembers("kpl_forbidden_plates")
 
 
class LimitUpCodesPlateKeyManager:
    # 今日涨停原因
    today_limit_up_reason_dict = {}
    today_total_limit_up_reason_dict = {}
    total_code_keys_dict = {}
    total_key_codes_dict = {}
    __redisManager = redis_manager.RedisManager(1)
 
    def __get_redis(self):
        return self.__redisManager.getRedis()
 
    # 获取今日涨停数据,格式:[(代码,涨停原因)]
    def set_today_limit_up(self, datas):
        temp_dict = {}
        if datas:
            for item in datas:
                temp_dict[item[0]] = item[1]
            self.today_limit_up_reason_dict = temp_dict
        if datas:
            for item in datas:
                self.__set_total_keys(item[0])
        self.set_today_total_limit_up(datas)
 
    # 设置今日历史涨停数据
    def set_today_total_limit_up(self, datas):
        for item in datas:
            code = item[0]
            self.today_total_limit_up_reason_dict[code] = item[1]
 
    # 今日涨停原因变化
    def set_today_limit_up_reason_change(self, code, from_reason, to_reason):
        self.__get_redis().sadd(f"kpl_limit_up_reason_his-{code}", from_reason)
        self.__get_redis().expire(f"kpl_limit_up_reason_his-{code}", tool.get_expire())
        self.__set_total_keys(code)
 
    def __set_total_keys(self, code):
        keys = set()
        keys_his = self.__get_redis().smembers(f"kpl_limit_up_reason_his-{code}")
        keys |= keys_his
        if code in self.today_limit_up_reason_dict:
            keys.add(self.today_limit_up_reason_dict.get(code))
        self.total_code_keys_dict[code] = keys
        for k in keys:
            if k not in self.total_key_codes_dict:
                self.total_key_codes_dict[k] = set()
            self.total_key_codes_dict[k].add(code)
 
        logger_kpl_limit_up.info("{}板块关键词:{}", code, keys)
 
    def get_codes_by_key_without_mine(self, key, code):
        # 只比较今日涨停原因
        codes_set = set()
        if key in self.total_key_codes_dict:
            codes_set |= self.total_key_codes_dict[key]
        codes_set.discard(code)
        return codes_set
 
    # 涨停原因匹配关键字(和涨停列表中的涨停原因做对比),返回:{关键词:代码集合}
    def match_limit_up_reason_keys(self, code, keys):
        fresult = {}
        for k in keys:
            if k in self.total_key_codes_dict:
                codes = set(self.total_key_codes_dict[k])
                codes.discard(code)
                if codes:
                    fresult[k] = codes
        return fresult
 
 
# 实时开盘啦市场数据
class RealTimeKplMarketData:
    # 精选前5
    top_5_reason_list = []
    # 行业前5
    top_5_industry_list = []
    #
    top_5_key_dict = {}
    total_reason_dict = {}
    total_industry_dict = {}
    __KPLPlateForbiddenManager = KPLPlateForbiddenManager()
    __LimitUpCodesPlateKeyManager = LimitUpCodesPlateKeyManager()
    __KPLPlatManager = KPLPlatManager()
 
    @classmethod
    def set_top_5_reasons(cls, datas):
        temp_list = []
        for d in datas:
            cls.total_reason_dict[d[1]] = d
        # 排序
        for i in range(0, len(datas)):
            if datas[i][1] not in constant.KPL_INVALID_BLOCKS:
                # (名称,净流入金额,排名)
                temp_list.append((datas[i][1], datas[i][3], len(temp_list)))
                # 只获取前10个
                if len(temp_list) > 5:
                    break
                if datas[i][3] < 1 * 10000 * 10000:
                    break
 
        for temp in temp_list:
            names = cls.__KPLPlatManager.get_same_plat_names_by_id(temp[0])
            for name in names:
                if name == temp[1]:
                    continue
                temp_list.append((name, temp[1], temp[2]))
        cls.top_5_reason_list = temp_list
        cls.__reset_top_5_dict()
 
    @classmethod
    def set_top_5_industry(cls, datas):
        for d in datas:
            cls.total_industry_dict[d[1]] = d
        temp_list = []
        for i in range(0, len(datas)):
            if datas[i][1] in constant.KPL_INVALID_BLOCKS:
                continue
            temp_list.append((datas[i][1], datas[i][2], len(temp_list)))
            if len(temp_list) > 5:
                break
            if datas[i][2] < 1 * 10000 * 10000:
                break
        cls.top_5_industry_list = temp_list
        cls.__reset_top_5_dict()
 
    @classmethod
    def __reset_top_5_dict(cls):
        temp_dict = {}
        for t in cls.top_5_industry_list:
            temp_dict[t[0]] = t
        for t in cls.top_5_reason_list:
            temp_dict[t[0]] = t
        cls.top_5_key_dict = temp_dict
 
    # 获取能够买的行业关键字set
    @classmethod
    def get_can_buy_key_set(cls):
        temp_set = cls.top_5_key_dict.keys()
        return temp_set
 
    # 通过关键字判断能买的代码数量
    @classmethod
    def get_can_buy_codes_count(cls, code, key):
        # 判断行业涨停票数量,除开自己必须大于1个
        temp_codes = LimitUpCodesPlateKeyManager.total_key_codes_dict.get(key)
        if temp_codes is None:
            temp_codes = set()
        else:
            temp_codes = set(temp_codes)
        temp_codes.discard(code)
        if len(temp_codes) < 1:
            # 后排才能挂单
            return 0, "身位不为后排"
 
        forbidden_plates = cls.__KPLPlateForbiddenManager.list_all()
        if key in forbidden_plates:
            return 0, "不买该板块"
 
        # 10:30以前可以挂2个单
        if int(tool.get_now_time_str().replace(':', '')) < int("100000"):
            return 2, "10:00以前可以挂2个单"
        # 10:30以后
        if key not in cls.top_5_key_dict:
            return 0, "净流入没在前5"
        if cls.top_5_key_dict[key][1] > 3 * 10000 * 10000:
            return 2, "净流入在前5且大于3亿"
        else:
            return 1, "净流入在前5"
 
    @classmethod
    def is_in_top(cls, keys):
        reasons = cls.get_can_buy_key_set()
        log.logger_kpl_debug.debug("市场流入前5:{}", reasons)
        forbidden_plates = cls.__KPLPlateForbiddenManager.list_all()
        reasons = reasons - forbidden_plates
        temp_set = keys & reasons
        log.logger_kpl_debug.debug("市场流入前5匹配结果:{}", temp_set)
        if temp_set:
            return True, temp_set
        else:
            return False, None
 
 
#
class CodesHisReasonAndBlocksManager:
    __redisManager = redis_manager.RedisManager(1)
    # 历史涨停原因
    __history_limit_up_reason_dict = {}
    # 板块
    __blocks_dict = {}
 
    def __get_redis(self):
        return self.__redisManager.getRedis()
 
    def set_history_limit_up_reason(self, code, reasons):
        self.__history_limit_up_reason_dict[code] = set(reasons)
        self.__get_redis().setex(f"kpl_his_limit_up_reason-{code}", tool.get_expire(), json.dumps(list(reasons)))
 
        # 如果返回值不为None表示已经加载过历史原因了
 
    def get_history_limit_up_reason(self, code):
        reasons = self.__history_limit_up_reason_dict.get(code)
        if reasons is None:
            # 从内存中加载
            val = self.__get_redis().get(f"kpl_his_limit_up_reason-{code}")
            if val is not None:
                val = set(json.loads(val))
                self.__history_limit_up_reason_dict[code] = val
            if code in self.__history_limit_up_reason_dict:
                return self.__history_limit_up_reason_dict.get(code)
            else:
                return None
        else:
            return reasons
 
    def set_blocks(self, code, blocks):
        self.__blocks_dict[code] = set(blocks)
        self.__get_redis().setex(f"kpl_blocks-{code}", tool.get_expire(), json.dumps(list(blocks)))
 
    def get_blocks(self, code):
        reasons = self.__blocks_dict.get(code)
        if reasons is None:
            # 从内存中加载
            val = self.__get_redis().get(f"kpl_blocks-{code}")
            if val is not None:
                val = set(json.loads(val))
                self.__blocks_dict[code] = val
            if code in self.__blocks_dict:
                return self.__blocks_dict.get(code)
            else:
                return None
        else:
            return reasons
 
    def get_total_keys(self, code):
        reasons = self.get_history_limit_up_reason(code)
        if reasons is None:
            reasons = set()
        blocks = self.get_blocks(code)
        if blocks is None:
            blocks = set()
        return reasons | blocks
 
 
# 目标代码关键词管理
class TargetCodePlateKeyManager:
    __redisManager = redis_manager.RedisManager(1)
    __CodesPlateKeysManager = CodesHisReasonAndBlocksManager()
 
    def __get_redis(self):
        return self.__redisManager.getRedis()
 
    # 返回key集合(排除无效板块),今日涨停原因,今日历史涨停原因,历史涨停原因,二级,板块
    def get_plate_keys(self, code):
        keys = set()
        k1 = set()
        if code in LimitUpCodesPlateKeyManager.today_total_limit_up_reason_dict:
            k1 = {LimitUpCodesPlateKeyManager.today_total_limit_up_reason_dict[code]}
        # 加载历史原因
        k11 = self.__get_redis().smembers(f"kpl_limit_up_reason_his-{code}")
        k2 = self.__CodesPlateKeysManager.get_history_limit_up_reason(code)
        if k2 is None:
            k2 = set()
        k3 = set()
        industry = global_util.code_industry_map.get(code)
        if industry:
            k3 = {industry}
 
        k4 = self.__CodesPlateKeysManager.get_blocks(code)
        if k4 is None:
            k4 = set()
        for k in [k1, k11, k2, k3, k4]:
            keys |= k
 
        # 排除无效的涨停原因
        keys = keys - set(constant.KPL_INVALID_BLOCKS)
 
        return keys, k1, k11, k2, k3, k4
 
 
class CodePlateKeyBuyManager:
    __TargetCodePlateKeyManager = TargetCodePlateKeyManager()
    __LimitUpCodesPlateKeyManager = LimitUpCodesPlateKeyManager()
    __CodesHisReasonAndBlocksManager = CodesHisReasonAndBlocksManager()
 
    # 是否可以下单
    @classmethod
    def can_buy(cls, code):
        if constant.TEST:
            return True, ""
        keys, k1, k11, k2, k3, k4 = cls.__TargetCodePlateKeyManager.get_plate_keys(code)
        log.logger_kpl_debug.info("{}关键词:{},{},{},{},{},{}", code, keys, k1, k11, k2, k3, k4)
        # 涨停列表中匹配关键词
        match_limit_up_result = cls.__LimitUpCodesPlateKeyManager.match_limit_up_reason_keys(code, keys)
        log.logger_kpl_debug.info("{}关键词身位匹配结果:{}", code, match_limit_up_result)
        if not match_limit_up_result:
            return False, "未在涨停列表中未匹配到涨停原因"
 
        # ---------------------------------判断目标代码的板块-------------------start------------
        # 判断匹配出的涨停原因,判断是否有已经下单的票
        # reason_need_buy_dict = {}
        # for k in match_limit_up_result:
        #     codes = match_limit_up_result[k]
        #     final_codes_keys = [keys]
        #     for code_ in codes:
        #         temp_key_set = set()
        #         temp_key_set |= cls.__CodesHisReasonAndBlocksManager.get_total_keys(code_)
        #         temp = cls.__LimitUpCodesPlateKeyManager.total_code_keys_dict.get(code_)
        #         if temp:
        #             temp_key_set |= temp
        #         # 二级
        #         industry = global_util.code_industry_map.get(code_)
        #         if industry:
        #             temp_key_set.add(industry)
        #
        #         final_codes_keys.append(temp_key_set)
        #     # 求共同的关键词
        #     intersection = set(final_codes_keys[0])
        #     for s in final_codes_keys:
        #         intersection &= s
        #     log.logger_kpl_debug.info("{}的板块求交集:{}-{}", code, k, intersection)
        #
        #     # 求公共的板块是否在流入前5中
        #     is_in, valid_keys = RealTimeKplMarketData.is_in_top(intersection)
        #     if is_in:
        #         reason_need_buy_dict[k] = (is_in, valid_keys)
        # ---------------------------------判断目标代码的板块-------------------end------------
 
        # 获取板块可以下单的个数
        can_buy_codes_count_dict = {}
 
        for key__ in match_limit_up_result:
            can_buy_count, msg = RealTimeKplMarketData.get_can_buy_codes_count(code, key__)
            can_buy_codes_count_dict[key__] = can_buy_count
 
        has_available_key = False
        for key in can_buy_codes_count_dict:
            if can_buy_codes_count_dict[key] > 0:
                has_available_key = True
                break
        if not has_available_key:
            return False, f"匹配到的【{','.join(match_limit_up_result.keys())}】没在精选/行业可以买入的板块中"
 
        # ---------------------------------加载已经下单/成交的代码信息------------start-------------
        match_reasons = match_limit_up_result.keys()
        # 判断匹配到的原因是否已经有下单/买入成功的代码
        codes_delegate = set(trade_manager.get_codes_by_trade_states(
            {trade_manager.TRADE_STATE_BUY_DELEGATED, trade_manager.TRADE_STATE_BUY_PLACE_ORDER}))
        codes_success = set(trade_manager.get_codes_by_trade_states(
            {trade_manager.TRADE_STATE_BUY_SUCCESS}))
 
        codes = codes_delegate | codes_success
 
        # 统计成交代码的板块
        trade_codes_blocks_dict = {}
        # 已经成交的板块
        trade_success_blocks = set()
        for c in codes:
            keys_, k1_, k11_, k2_, k3_, k4_ = cls.__TargetCodePlateKeyManager.get_plate_keys(c)
            # 实时涨停原因
            trade_codes_blocks_dict[c] = k1_
        # 统计板块中的代码
        trade_block_codes_dict = {}
        for c in trade_codes_blocks_dict:
            for b in trade_codes_blocks_dict[c]:
                if c in codes_success:
                    trade_success_blocks.add(b)
                if b not in trade_block_codes_dict:
                    trade_block_codes_dict[b] = set()
                trade_block_codes_dict[b].add(c)
 
        # ---------------------------------加载已经下单/成交的代码信息------------end-------------
 
        msg_list = []
        for key in can_buy_codes_count_dict:
            log.logger_kpl_debug.debug(f"{code}:板块可以下单的数量【{key}】-{can_buy_codes_count_dict[key]}")
            if can_buy_codes_count_dict[key] < 1:
                continue
            # 板块中已经有成交的就不下单了
            if key in trade_success_blocks:
                msg_list.append(f"【{key}】中已经有成交代码")
                log.logger_kpl_debug.debug(f"{code}:板块已经有成交【{key}】")
                continue
            # 板块可以下单数量
            if trade_block_codes_dict.get(key) is None or len(trade_block_codes_dict.get(key)) < \
                    can_buy_codes_count_dict[key]:
                order_count = len(trade_block_codes_dict.get(key)) if key in trade_block_codes_dict else 0
                logger_kpl_block_can_buy.info(
                    f"code={code}:【{key}】可以下单,现有数量:{order_count} 最大数量:{can_buy_codes_count_dict[key]}")
                return True, f"可以下单,板块:【{key}】,板块中已经下单的数量:{order_count}"
            else:
                order_count = len(trade_block_codes_dict.get(key))
                msg_list.append(f"【{key}】中下单代码数量{order_count}/允许下单数量{can_buy_codes_count_dict[key]}")
 
        return False, ",".join(msg_list)
 
 
if __name__ == "__main__":
    pass