| | |
| | | import json |
| | | |
| | | import constant |
| | | import global_data_loader |
| | | import global_util |
| | | import log |
| | | import tool |
| | | from db import redis_manager |
| | | |
| | | from log import logger_kpl_limit_up |
| | | from log import logger_kpl_limit_up, logger_kpl_block_can_buy |
| | | from third_data.kpl_util import KPLPlatManager |
| | | from trade import trade_manager |
| | | |
| | | |
| | | # 实时开盘啦市场数据 |
| | | class RealTimeKplMarketData: |
| | | # 精选前5 |
| | | top_5_reason_set = set() |
| | | # 行业前5 |
| | | top_5_industry_set = set() |
| | | # 开盘啦禁止交易板块管理 |
| | | class KPLPlateForbiddenManager: |
| | | __redisManager = redis_manager.RedisManager(3) |
| | | |
| | | @classmethod |
| | | def set_top_5_reasons(cls, datas): |
| | | temp_set = set() |
| | | base_count = 5 |
| | | for i in range(0, len(datas)): |
| | | if datas[i][1] in constant.KPL_INVALID_BLOCKS: |
| | | base_count += 1 |
| | | if i >= base_count: |
| | | break |
| | | if datas[i][3] > 5000 * 10000: |
| | | temp_set.add(datas[i][1]) |
| | | cls.top_5_reason_set = temp_set |
| | | def __get_redis(self): |
| | | return self.__redisManager.getRedis() |
| | | |
| | | @classmethod |
| | | def set_top_5_industry(cls, datas): |
| | | temp_set = set() |
| | | base_count = 5 |
| | | for i in range(0, len(datas)): |
| | | if datas[i][1] in constant.KPL_INVALID_BLOCKS: |
| | | base_count += 1 |
| | | if i >= base_count: |
| | | break |
| | | def save_plate(self, plate): |
| | | self.__get_redis().sadd("kpl_forbidden_plates", plate) |
| | | self.__get_redis().expire("kpl_forbidden_plates", tool.get_expire()) |
| | | |
| | | if datas[i][2] > 5000 * 10000: |
| | | temp_set.add(datas[i][1]) |
| | | cls.top_5_reason_set = temp_set |
| | | |
| | | # 获取能够买的行业关键字set |
| | | @classmethod |
| | | def get_can_buy_key_set(cls): |
| | | temp_set = cls.top_5_reason_set | cls.top_5_industry_set |
| | | return temp_set |
| | | |
| | | @classmethod |
| | | def is_in_top(cls, keys): |
| | | reasons = cls.get_can_buy_key_set() |
| | | temp_set = keys & reasons |
| | | if temp_set: |
| | | return True, temp_set |
| | | else: |
| | | return False, None |
| | | def list_all(self): |
| | | return self.__get_redis().smembers("kpl_forbidden_plates") |
| | | |
| | | |
| | | class LimitUpCodesPlateKeyManager: |
| | |
| | | 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 TargetCodePlateKeyManager: |
| | | |
| | | # 实时开盘啦市场数据 |
| | | 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("103000"): |
| | | return 2, "10:30以前可以挂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 = {} |
| | | # 二级行业 |
| | | __second_industry_dict = {} |
| | | # 板块 |
| | | __blocks_dict = {} |
| | | |
| | |
| | | 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表示已经加载过历史原因了 |
| | | # 如果返回值不为None表示已经加载过历史原因了 |
| | | |
| | | def get_history_limit_up_reason(self, code): |
| | | reasons = self.__history_limit_up_reason_dict.get(code) |
| | | if reasons is None: |
| | |
| | | if val is not None: |
| | | val = set(json.loads(val)) |
| | | self.__history_limit_up_reason_dict[code] = val |
| | | return self.__history_limit_up_reason_dict.get(code) |
| | | if code in self.__history_limit_up_reason_dict: |
| | | return self.__history_limit_up_reason_dict.get(code) |
| | | else: |
| | | return None |
| | | else: |
| | | return reasons |
| | | |
| | |
| | | if val is not None: |
| | | val = set(json.loads(val)) |
| | | self.__blocks_dict[code] = val |
| | | return self.__blocks_dict.get(code) |
| | | 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): |
| | |
| | | k1 = {LimitUpCodesPlateKeyManager.today_total_limit_up_reason_dict[code]} |
| | | # 加载历史原因 |
| | | k11 = self.__get_redis().smembers(f"kpl_limit_up_reason_his-{code}") |
| | | k2 = set() |
| | | if code in self.__history_limit_up_reason_dict: |
| | | k2 = self.__history_limit_up_reason_dict[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 = set() |
| | | if code in self.__blocks_dict: |
| | | k4 = self.__blocks_dict[code] |
| | | k4 = self.__CodesPlateKeysManager.get_blocks(code) |
| | | if k4 is None: |
| | | k4 = set() |
| | | for k in [k1, k11, k2, k3, k4]: |
| | | keys |= k |
| | | |
| | |
| | | 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) |
| | | # 板块Key是否在市场前5key中 |
| | | is_in, valid_keys = RealTimeKplMarketData.is_in_top(keys) |
| | | if not valid_keys: |
| | | return False, "板块未在市场流入前5" |
| | | # 相同板块中是否已经有别的票涨停 |
| | | is_back = False, '' |
| | | for key in valid_keys: |
| | | codes = cls.__LimitUpCodesPlateKeyManager.get_codes_by_key_without_mine(key, code) |
| | | if codes and len(codes) > 0: |
| | | is_back = True, key |
| | | 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 is_back[0]: |
| | | return False, f"板块中首个涨停:{valid_keys}" |
| | | # 看板块中是否已经有已经下单的或者成交的代码 |
| | | codes = trade_manager.get_codes_by_trade_states( |
| | | {trade_manager.TRADE_STATE_BUY_DELEGATED, trade_manager.TRADE_STATE_BUY_PLACE_ORDER, |
| | | trade_manager.TRADE_STATE_BUY_SUCCESS}) |
| | | # 遍历已经成交/下单的代码,获取其涨停原因,然后和当前代码涨停原因做比较,有相同代码的不能买 |
| | | 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) |
| | | # 实时涨停原因 |
| | | for k_ in k1_: |
| | | # 当前代码已经有挂的或者成交的 |
| | | if k_ in valid_keys: |
| | | return False, f"{k_}板块中的{c}已经下单/买入成功,同一板块中只能买1个票" |
| | | return True, f"涨停原因:{is_back[1]}" |
| | | 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__": |
| | | datas = log.load_kpl_reason_changes() |
| | | for k in datas: |
| | | LimitUpCodesPlateKeyManager().set_today_limit_up_reason_change(k[0], k[1], k[2]) |
| | | pass |