| | |
| | | # 涨停代码关键词板块管理 |
| | | import copy |
| | | import datetime |
| | | import itertools |
| | | import json |
| | | import time |
| | | |
| | | import constant |
| | | from code_attribute import gpcode_manager |
| | | from db.redis_manager_delegate import RedisUtils |
| | | from third_data import kpl_block_util, kpl_api, kpl_util, kpl_data_constant, huaxin_l1_data_manager |
| | | from third_data import kpl_block_util, kpl_api, kpl_util |
| | | from settings.trade_setting import MarketSituationManager |
| | | from third_data.kpl_data_constant import LimitUpDataConstant, LimitUpCodesBlockRecordManager |
| | | from third_data.third_blocks_manager import BlockMapManager, CodeThirdBlocksManager |
| | | from trade.buy_money_count_setting import RadicalBuyBlockCodeCountManager |
| | | from trade.order_statistic import DealAndDelegateWithBuyModeDataManager |
| | | from trade.radical_buy_data_manager import RedicalBuyDataManager |
| | | from third_data.history_k_data_manager import HistoryKDataManager |
| | | from third_data.history_k_data_util import HistoryKDatasUtils |
| | | from third_data.kpl_data_constant import LimitUpCodesBlockRecordManager, ContainsLimitupCodesBlocksManager |
| | | from third_data.third_blocks_manager import BlockMapManager |
| | | from utils import global_util, tool, buy_condition_util |
| | | from log_module import log, async_log_util |
| | | from db import redis_manager_delegate as redis_manager |
| | | from log_module import async_log_util |
| | | from db import redis_manager_delegate as redis_manager, mysql_data_delegate as mysql_data |
| | | |
| | | from log_module.log import logger_kpl_block_can_buy, logger_debug, logger_kpl_jx_out |
| | | from log_module.log import logger_kpl_block_can_buy, logger_kpl_jx_out, logger_kpl_jx_in, logger_debug, \ |
| | | logger_kpl_latest_gaobiao |
| | | from third_data.kpl_util import KPLPlatManager |
| | | from trade import trade_manager, l2_trade_util, trade_constant |
| | | from trade import l2_trade_util, trade_constant |
| | | |
| | | # 代码精选板块管理 |
| | | from utils.kpl_data_db_util import KPLLimitUpDataUtil |
| | |
| | | def __new__(cls, *args, **kwargs): |
| | | if not cls.__instance: |
| | | cls.__instance = super(KPLCodeJXBlockManager, cls).__new__(cls, *args, **kwargs) |
| | | cls.__load_data() |
| | | try: |
| | | cls.__load_data() |
| | | except Exception as e: |
| | | logger_debug.exception(e) |
| | | return cls.__instance |
| | | |
| | | @classmethod |
| | |
| | | |
| | | # 开盘啦禁止交易板块管理 |
| | | class KPLPlateForbiddenManager: |
| | | __redisManager = redis_manager.RedisManager(3) |
| | | """ |
| | | 不能买的板块管理 |
| | | """ |
| | | __redis_manager = redis_manager.RedisManager(3) |
| | | __kpl_forbidden_plates_cache = set() |
| | | # 已经删除了的板块 |
| | | __deleted_kpl_forbidden_plates_cache = set() |
| | | |
| | | # 监控的高标板块代码字典:{"板块":{"代码1","代码2"}} |
| | | __watch_block_high_codes = {} |
| | | # 高标代码 |
| | | __watch_high_codes = set() |
| | | |
| | | __instance = None |
| | | |
| | |
| | | def __load_datas(cls): |
| | | __redis = cls.__get_redis() |
| | | try: |
| | | __kpl_forbidden_plates_cache = RedisUtils.smembers(__redis, "kpl_forbidden_plates") |
| | | cls.__kpl_forbidden_plates_cache = RedisUtils.smembers(__redis, "kpl_forbidden_plates") |
| | | cls.__deleted_kpl_forbidden_plates_cache = RedisUtils.smembers(__redis, "deleted_kpl_forbidden_plates") |
| | | finally: |
| | | RedisUtils.realse(__redis) |
| | | cls.__load_latest_gb() |
| | | |
| | | @classmethod |
| | | def __get_redis(cls): |
| | | return cls.__redisManager.getRedis() |
| | | return cls.__redis_manager.getRedis() |
| | | |
| | | def save_plate(self, plate): |
| | | self.__kpl_forbidden_plates_cache.add(plate) |
| | | RedisUtils.sadd(self.__get_redis(), "kpl_forbidden_plates", plate) |
| | | RedisUtils.expire(self.__get_redis(), "kpl_forbidden_plates", tool.get_expire()) |
| | | |
| | | self.__deleted_kpl_forbidden_plates_cache.discard(plate) |
| | | RedisUtils.srem(self.__get_redis(), "deleted_kpl_forbidden_plates", plate) |
| | | RedisUtils.expire(self.__get_redis(), "deleted_kpl_forbidden_plates", tool.get_expire()) |
| | | |
| | | def delete_plate(self, plate): |
| | | self.__kpl_forbidden_plates_cache.discard(plate) |
| | | RedisUtils.srem(self.__get_redis(), "kpl_forbidden_plates", plate) |
| | | RedisUtils.expire(self.__get_redis(), "kpl_forbidden_plates", tool.get_expire()) |
| | | self.__deleted_kpl_forbidden_plates_cache.add(plate) |
| | | RedisUtils.sadd(self.__get_redis(), "deleted_kpl_forbidden_plates", plate) |
| | | RedisUtils.expire(self.__get_redis(), "deleted_kpl_forbidden_plates", tool.get_expire()) |
| | | |
| | | def list_all(self): |
| | | return RedisUtils.smembers(self.__get_redis(), "kpl_forbidden_plates") |
| | | |
| | | def list_all_cache(self): |
| | | return self.__kpl_forbidden_plates_cache |
| | | |
| | | def list_all_deleted_cache(self): |
| | | return self.__deleted_kpl_forbidden_plates_cache |
| | | |
| | | def is_in_cache(self, plate): |
| | | if self.__kpl_forbidden_plates_cache and plate in self.__kpl_forbidden_plates_cache: |
| | | return True |
| | | return False |
| | | |
| | | @classmethod |
| | | def __load_latest_gb(cls): |
| | | """ |
| | | 加载最近的市场高标 |
| | | @return: |
| | | """ |
| | | # 获取最近10个交易日涨停的涨停数据 |
| | | dates = HistoryKDatasUtils.get_latest_trading_date_cache(10) |
| | | if not dates: |
| | | return |
| | | min_date = dates[-1] |
| | | sql = f"SELECT r.`_code`, r.`_hot_block_name`, r.`_day`, r.`_open` FROM `kpl_limit_up_record` r WHERE r.`_day`>='{min_date}'" |
| | | mysqldb = mysql_data.Mysqldb() |
| | | results = mysqldb.select_all(sql) |
| | | code_days_map = {} |
| | | # 每炸板 |
| | | f_code_days_map = {} |
| | | for r in results: |
| | | if r[0] not in code_days_map: |
| | | code_days_map[r[0]] = set() |
| | | code_days_map[r[0]].add(r[2]) |
| | | if not r[3]: |
| | | if r[0] not in f_code_days_map: |
| | | f_code_days_map[r[0]] = set() |
| | | f_code_days_map[r[0]].add(r[2]) |
| | | |
| | | # 过滤涨停次数>=3次的数据 |
| | | target_codes = set() |
| | | for code in code_days_map: |
| | | if f_code_days_map.get(code) and (len(f_code_days_map.get(code)) >= 4 or ( |
| | | tool.is_ge_code(code) and len(f_code_days_map.get(code)) >= 2)): |
| | | # 且有3天属于连续涨停 |
| | | day_list = list(code_days_map[code]) |
| | | day_list.sort(reverse=True) |
| | | step = 3 |
| | | has_continue = False |
| | | for i in range(0, len(day_list) - step + 1): |
| | | item_list = day_list[i:i + step] |
| | | # 是否属于连续涨停 |
| | | is_sub = False |
| | | for j in range(0, len(dates) - step): |
| | | if f"{dates[j:j + step]}" == f"{item_list}": |
| | | is_sub = True |
| | | break |
| | | if is_sub: |
| | | has_continue = True |
| | | break |
| | | if not has_continue: |
| | | continue |
| | | |
| | | has_big_deal = False |
| | | # 最近10个交易日的成交额要大于10亿 |
| | | volumes_data = HistoryKDataManager().get_history_bars(code, dates[0]) |
| | | if volumes_data: |
| | | for d in volumes_data[:10]: |
| | | if d["amount"] > 10e8: |
| | | has_big_deal = True |
| | | break |
| | | if not has_big_deal: |
| | | continue |
| | | target_codes.add(code) |
| | | # 代码对应的板块 |
| | | code_blocks = {} |
| | | for r in results: |
| | | if r[0] not in target_codes: |
| | | continue |
| | | if r[0] not in code_blocks: |
| | | code_blocks[r[0]] = set() |
| | | code_blocks[r[0]].add(kpl_util.filter_block(r[1])) |
| | | # 所有板块对应的代码集合 |
| | | block_codes = {} |
| | | for code in code_blocks: |
| | | for b in code_blocks[code]: |
| | | if b in constant.KPL_INVALID_BLOCKS: |
| | | continue |
| | | if b not in block_codes: |
| | | block_codes[b] = set() |
| | | block_codes[b].add(code) |
| | | print(block_codes) |
| | | cls.__watch_block_high_codes = block_codes |
| | | logger_kpl_latest_gaobiao.info(f"{block_codes}") |
| | | cls.__watch_high_codes.clear() |
| | | for b in block_codes: |
| | | cls.__watch_high_codes |= block_codes[b] |
| | | |
| | | for k in block_codes: |
| | | print(k, [(x, gpcode_manager.get_code_name(x)) for x in block_codes[k]]) |
| | | |
| | | def get_watch_high_codes(self): |
| | | return self.__watch_high_codes |
| | | |
| | | def get_watch_high_codes_by_block(self, b): |
| | | return self.__watch_block_high_codes.get(b) |
| | | |
| | | def compute(self, code_rate_dict: dict): |
| | | """ |
| | | 根据比例计算需要拉黑的代码 |
| | | @param code_rate_dict: 涨幅百分数 |
| | | @return: |
| | | """ |
| | | try: |
| | | if self.__watch_block_high_codes: |
| | | forbidden_blocks = set() |
| | | for b in self.__watch_block_high_codes: |
| | | total_rate = 0 |
| | | for code in self.__watch_block_high_codes[b]: |
| | | if code in code_rate_dict: |
| | | total_rate += code_rate_dict.get(code) |
| | | average_rate = total_rate / len(self.__watch_block_high_codes[b]) |
| | | if average_rate < 1: |
| | | forbidden_blocks.add(b) |
| | | # async_log_util.info(logger_debug, f"板块平均涨幅 {b}-{average_rate}") |
| | | |
| | | self.__kpl_forbidden_plates_cache = forbidden_blocks |
| | | async_log_util.info(logger_debug, f"拉黑板块:{forbidden_blocks}") |
| | | except Exception as e: |
| | | logger_debug.exception(e) |
| | | |
| | | |
| | | class LimitUpCodesPlateKeyManager: |
| | |
| | | |
| | | # 实时开盘啦市场数据 |
| | | class RealTimeKplMarketData: |
| | | # 精选前5 |
| | | top_5_reason_list = [] |
| | | # 流入缓存 [ID, 板块名称, 板块涨幅, 流入金额] |
| | | top_in_list_cache = [] |
| | | # 流出缓存 |
| | | top_out_list_cache = [] |
| | | # 行业前5 |
| | | top_5_industry_list = [] |
| | | # |
| | |
| | | __LimitUpCodesPlateKeyManager = LimitUpCodesPlateKeyManager() |
| | | __KPLPlatManager = KPLPlatManager() |
| | | # 精选流入前几 |
| | | __top_jx_blocks = set() |
| | | __top_jx_blocks = [] |
| | | # 精选流出前几 |
| | | __top_jx_out_blocks = set() |
| | | __top_jx_out_blocks = [] |
| | | # 精选板块流入金额 |
| | | __jx_blocks_in_money_dict = {} |
| | | # 市场行情热度,默认为60 |
| | | __market_strong = 60 |
| | | |
| | | @classmethod |
| | | def get_jingxuan_in_block_threshold_count(cls): |
| | | """ |
| | | 获取买精选流入前几 |
| | | @return: |
| | | """ |
| | | score = 60 |
| | | if cls.__market_strong is not None: |
| | | score = int(cls.__market_strong) |
| | | for info in constant.RADICAL_BUY_TOP_IN_COUNT_BY_MARKET_STRONG: |
| | | if info[0] <= score < info[1]: |
| | | return info[2] |
| | | return 10 |
| | | |
| | | @classmethod |
| | | def set_market_jingxuan_blocks(cls, datas): |
| | | """ |
| | | 设置精选流入数据 |
| | | @param datas: |
| | | @param datas:[(板块编号,板块名称,涨幅, 板块流入金额)] |
| | | @return: |
| | | """ |
| | | # 流入阈值 |
| | | # THRESHOLD_MONEY = 50 * (tool.trade_time_sub(tool.get_now_time_str(), "09:30:00") // 60) + 1000 |
| | | # THRESHOLD_MONEY = min(THRESHOLD_MONEY, 10000) |
| | | # THRESHOLD_MONEY = max(THRESHOLD_MONEY, 1000) |
| | | # THRESHOLD_MONEY = THRESHOLD_MONEY * 10000 |
| | | THRESHOLD_MONEY = 0 |
| | | # 最大数量 |
| | | # MAX_COUNT = cls.get_jingxuan_in_block_threshold_count() |
| | | |
| | | cls.top_in_list_cache = datas |
| | | blocks = set() |
| | | count = 0 |
| | | fblock_money = {} |
| | | for data in datas: |
| | | if data[3] <= 0: |
| | | break |
| | | blocks.add(data[1]) |
| | | cls.__jx_blocks_in_money_dict[data[1]] = data[3] |
| | | if data[1] in constant.KPL_INVALID_BLOCKS: |
| | | continue |
| | | if data[3] < THRESHOLD_MONEY: |
| | | continue |
| | | # 过滤出来为同一个板块就只算1个数量 |
| | | fb = BlockMapManager().filter_blocks({data[1]}) |
| | | if blocks & fb: |
| | | continue |
| | | |
| | | for b in fb: |
| | | fblock_money[b] = data[3] |
| | | blocks |= fb |
| | | |
| | | # 如果该原因没有涨停票要往后移一位 |
| | | has_code = False |
| | | for b in fb: |
| | | if ContainsLimitupCodesBlocksManager().get_block_codes(b): |
| | | has_code = True |
| | | break |
| | | if has_code: |
| | | count += 1 |
| | | if count == 10: |
| | | strong = cls.get_market_strong() |
| | | if strong is None: |
| | | strong = 60 |
| | | if data[3] > 3e7: |
| | | # 大于3千万 |
| | | THRESHOLD_MONEY = int((1 - strong / 200) * data[3]) |
| | | else: |
| | | THRESHOLD_MONEY = data[3] |
| | | # if count >= MAX_COUNT: |
| | | # break |
| | | # 记录精选流出日志 |
| | | async_log_util.info(logger_kpl_jx_in, f"原数据:{datas[:50]} 板块:{blocks}") |
| | | blocks = list(blocks) |
| | | blocks.sort(key=lambda x: fblock_money.get(x), reverse=True) |
| | | cls.__top_jx_blocks = blocks |
| | | |
| | | @classmethod |
| | |
| | | @param datas: |
| | | @return: |
| | | """ |
| | | cls.top_out_list_cache = datas |
| | | count = 0 |
| | | blocks = set() |
| | | for i in range(0, len(datas)): |
| | | if i >= 10 and int(tool.get_now_time_str().replace(":", "")) < int("100000"): |
| | | # 10点前看前10,十点后不看前10 |
| | | break |
| | | data = datas[i] |
| | | if data[3] > 0 - 5e7: |
| | | for data in datas: |
| | | cls.__jx_blocks_in_money_dict[data[1]] = data[3] |
| | | if data[1] in constant.KPL_INVALID_BLOCKS: |
| | | continue |
| | | if data[3] > -5e7: |
| | | # 过滤5千万以上的 |
| | | break |
| | | blocks.add(kpl_util.filter_block(data[1])) |
| | | |
| | | # 过滤出来为同一个板块就只算1个数量 |
| | | fb = BlockMapManager().filter_blocks({data[1]}) |
| | | if blocks & fb: |
| | | continue |
| | | blocks |= fb |
| | | count += 1 |
| | | if count >= 10: |
| | | break |
| | | # 记录精选流出日志 |
| | | async_log_util.info(logger_kpl_jx_out, f"原数据:{datas[:10]} 板块:{blocks}") |
| | | cls.__top_jx_out_blocks = blocks |
| | | cls.__top_jx_out_blocks = list(blocks) |
| | | |
| | | @classmethod |
| | | def set_market_strong(cls, strong): |
| | | """ |
| | | 设置市场行情强度 |
| | | @param strong: |
| | | @return: |
| | | """ |
| | | cls.__market_strong = strong |
| | | |
| | | @classmethod |
| | | def is_ignore_block_in_money(cls): |
| | | if cls.__market_strong and cls.__market_strong >= constant.IGNORE_BLOCK_IN_MONEY_MARKET_STRONG: |
| | | return True |
| | | return False |
| | | |
| | | @classmethod |
| | | def get_market_strong(cls): |
| | | return cls.__market_strong |
| | | |
| | | @classmethod |
| | | def get_top_market_jingxuan_blocks(cls): |
| | |
| | | @classmethod |
| | | def get_top_market_jingxuan_out_blocks(cls): |
| | | return cls.__top_jx_out_blocks |
| | | |
| | | @classmethod |
| | | def get_block_info_at_block_in(cls, b): |
| | | """ |
| | | 获取板块的净流入情况 |
| | | @param b: |
| | | @return: (板块名称,身位,流入金额) |
| | | """ |
| | | for i in range(0, len(cls.top_in_list_cache)): |
| | | if cls.top_in_list_cache[i][1] == b: |
| | | return b, i, cls.top_in_list_cache[i][3] |
| | | return b, -1, 0 |
| | | |
| | | @classmethod |
| | | def set_top_5_industry(cls, datas): |
| | |
| | | return True, temp_set |
| | | else: |
| | | return False, None |
| | | |
| | | @classmethod |
| | | def get_jx_block_in_money(cls, block): |
| | | return cls.__jx_blocks_in_money_dict.get(block) |
| | | |
| | | |
| | | # 代码历史涨停原因与板块管理 |
| | |
| | | __TargetCodePlateKeyManager = TargetCodePlateKeyManager() |
| | | __LimitUpCodesPlateKeyManager = LimitUpCodesPlateKeyManager() |
| | | __CodesHisReasonAndBlocksManager = CodesHisReasonAndBlocksManager() |
| | | __CodesTradeStateManager = trade_manager.CodesTradeStateManager() |
| | | __can_buy_compute_result_dict = {} |
| | | |
| | | @classmethod |
| | | def __remove_from_l2(cls, code, msg): |
| | | # 根据身位移除代码 |
| | | # return |
| | | # 下过单的代码不移除 |
| | | if trade_manager.CodesTradeStateManager().get_trade_state_cache(code) != trade_constant.TRADE_STATE_NOT_TRADE: |
| | | # 只要下过单的就不移除 |
| | | return |
| | | l2_trade_util.forbidden_trade(code, msg=msg) |
| | | logger_kpl_block_can_buy.info(msg) |
| | | |
| | | # 是否需要积极买 |
| | | @classmethod |
| | |
| | | |
| | | # 获取目标代码板块 |
| | | # keys, k1, k11, k2, k3, k4 = cls.__TargetCodePlateKeyManager.get_plate_keys(code) |
| | | keys, k1 = RadicalBuyBlockManager.get_code_blocks(code) |
| | | keys = LimitUpCodesBlockRecordManager().get_radical_buy_blocks(code) |
| | | if not keys: |
| | | keys = set() |
| | | keys = BlockMapManager().filter_blocks(keys) |
| | | if keys: |
| | | keys -= constant.KPL_INVALID_BLOCKS |
| | | |
| | | # log.logger_kpl_debug.info("{}最终关键词:{}", code, keys) |
| | | |
| | |
| | | @classmethod |
| | | def __compute_can_buy_blocks(cls, code, current_limit_up_datas, limit_up_record_datas, |
| | | yesterday_current_limit_up_codes, before_blocks_dict, |
| | | current_limit_up_block_codes_dict, high_level_general_code_blocks): |
| | | current_limit_up_block_codes_dict, high_level_general_code_blocks, codes_delegate, |
| | | codes_success): |
| | | # 根据代码泛化板块获取泛化板块的代码集合 |
| | | high_level_general_block_codes = {} |
| | | for c in high_level_general_code_blocks: |
| | |
| | | high_level_general_block_codes) |
| | | if not blocks_compute_results: |
| | | return False, True, f"没有找到板块", [], keys, [] |
| | | codes_delegate = set(cls.__CodesTradeStateManager.get_codes_by_trade_states_cache( |
| | | {trade_constant.TRADE_STATE_BUY_DELEGATED, trade_constant.TRADE_STATE_BUY_PLACE_ORDER})) |
| | | codes_success = set(cls.__CodesTradeStateManager.get_codes_by_trade_states_cache( |
| | | {trade_constant.TRADE_STATE_BUY_SUCCESS})) |
| | | |
| | | codes = codes_delegate | codes_success |
| | | # 统计成交代码的板块 |
| | | trade_codes_blocks_dict = {} |
| | |
| | | @classmethod |
| | | def update_can_buy_blocks(cls, code, current_limit_up_datas, limit_up_record_datas, |
| | | latest_current_limit_up_records, |
| | | before_blocks_dict, current_limit_up_block_codes_dict): |
| | | before_blocks_dict, current_limit_up_block_codes_dict, delegate_codes, deal_codes): |
| | | yesterday_current_limit_up_codes = set() |
| | | yesterday_current_limit_up_records_dict = {} |
| | | yesterday_current_limit_up_records = latest_current_limit_up_records[0][1] |
| | |
| | | yesterday_current_limit_up_codes, |
| | | before_blocks_dict, |
| | | current_limit_up_block_codes_dict, |
| | | high_level_general_code_blocks) |
| | | high_level_general_code_blocks, |
| | | delegate_codes, |
| | | deal_codes) |
| | | # 保存板块计算结果 |
| | | cls.__can_buy_compute_result_dict[code] = ( |
| | | can_buy_blocks, unique, msg, can_buy_strong_blocks, keys, active_buy_blocks) |
| | | |
| | | |
| | | class RadicalBuyBlockManager: |
| | | """ |
| | | 扫入买板块管理 |
| | | """ |
| | | __TargetCodePlateKeyManager = TargetCodePlateKeyManager() |
| | | # 上次的涨停代码 |
| | | __last_limit_up_codes = set() |
| | | # 记录代码的涨停时间 |
| | | __limit_up_time_dict = {} |
| | | # 炸板代码的总涨停时间 |
| | | __total_limit_up_space_dict = {} |
| | | |
| | | # 当前涨停的代码 |
| | | __current_limit_up_codes = set() |
| | | |
| | | @classmethod |
| | | def set_current_limit_up_datas(cls, current_limit_up_datas): |
| | | # 查询当前的涨停代码集合 |
| | | codes = set([d[0] for d in current_limit_up_datas]) |
| | | cls.__current_limit_up_codes = codes |
| | | try: |
| | | # 炸板代码 |
| | | break_limit_up_codes = cls.__last_limit_up_codes - codes |
| | | # 新涨停的代码 |
| | | new_limit_up_codes = codes - cls.__last_limit_up_codes |
| | | if new_limit_up_codes: |
| | | for code in new_limit_up_codes: |
| | | if code not in cls.__limit_up_time_dict: |
| | | cls.__limit_up_time_dict[code] = time.time() |
| | | if break_limit_up_codes: |
| | | # 记录总涨停时间 |
| | | for bc in break_limit_up_codes: |
| | | if bc in cls.__limit_up_time_dict: |
| | | space = tool.trade_time_sub(tool.get_now_time_str(), |
| | | tool.to_time_str(cls.__limit_up_time_dict[bc])) |
| | | if bc not in cls.__total_limit_up_space_dict: |
| | | cls.__total_limit_up_space_dict[bc] = 0 |
| | | cls.__total_limit_up_space_dict[bc] = cls.__total_limit_up_space_dict[bc] + space |
| | | logger_debug.info(f"炸板代码涨停时间:{bc}-{cls.__total_limit_up_space_dict[bc]}") |
| | | cls.__limit_up_time_dict.pop(bc) |
| | | except Exception as e: |
| | | logger_debug.exception(e) |
| | | finally: |
| | | cls.__last_limit_up_codes = codes |
| | | cls.compute_open_limit_up_code_dict_for_radical_buy(current_limit_up_datas) |
| | | |
| | | @classmethod |
| | | def compute_open_limit_up_code_dict_for_radical_buy(cls, current_limit_up_datas): |
| | | """ |
| | | 计算开1的代码信息,不包含5板以上的 |
| | | @param current_limit_up_datas: |
| | | @return: |
| | | """ |
| | | timestamp_start, timestamp_end = kpl_block_util.open_limit_up_time_range |
| | | temp_dict = {} |
| | | for d in current_limit_up_datas: |
| | | code = d[0] |
| | | # d: (代码, 名称, 首次涨停时间, 最近涨停时间, 几板, 涨停原因, 板块, 实际流通, 主力净额,涨停原因代码,涨停原因代码数量) |
| | | # 计算是否开1 |
| | | if int(d[2]) >= timestamp_end or int(d[2]) < timestamp_start: |
| | | continue |
| | | buy1_money = huaxin_l1_data_manager.get_buy1_money(code) |
| | | # 买1是否大于5000w |
| | | if not constant.TEST: |
| | | if not buy1_money or buy1_money < 5e7: |
| | | continue |
| | | if not tool.is_can_buy_code(code): |
| | | continue |
| | | blocks = {d[5]} |
| | | if d[6]: |
| | | blocks |= set(d[6].split("、")) |
| | | blocks -= constant.KPL_INVALID_BLOCKS |
| | | # 过滤 |
| | | blocks = BlockMapManager().filter_blocks(blocks) |
| | | temp_dict[code] = (kpl_util.get_high_level_count(d[4]), blocks) |
| | | kpl_data_constant.open_limit_up_code_dict_for_radical_buy = temp_dict |
| | | |
| | | @classmethod |
| | | def __get_current_index(cls, code, block, yesterday_limit_up_codes, exclude_codes=None, limit_up_time=None): |
| | | """ |
| | | 获取当前涨停身位 |
| | | @param code: |
| | | @param block: |
| | | @param yesterday_limit_up_codes: |
| | | @return: 索引,前排代码信息([(代码, 涨停时间)]) |
| | | """ |
| | | if exclude_codes is None: |
| | | exclude_codes = set() |
| | | current_index = 0 |
| | | block_codes_infos = [] |
| | | timestamp_start, timestamp_end = kpl_block_util.open_limit_up_time_range |
| | | if limit_up_time is None: |
| | | limit_up_time = time.time() |
| | | for k in LimitUpDataConstant.current_limit_up_datas: |
| | | _code = k[0] |
| | | # 剔除4板以上的板 |
| | | if kpl_util.get_high_level_count(k[4]) >= 4: |
| | | continue |
| | | |
| | | if _code in exclude_codes: |
| | | continue |
| | | blocks = LimitUpDataConstant.get_blocks_with_history(_code) |
| | | if not blocks: |
| | | blocks = set() |
| | | blocks = BlockMapManager().filter_blocks(blocks) |
| | | if _code == code: |
| | | # 获取当前代码涨停时间 |
| | | limit_up_time = int(k[2]) |
| | | continue |
| | | # 不是这个板块 |
| | | if block not in blocks: |
| | | continue |
| | | if not tool.is_can_buy_code(_code): |
| | | continue |
| | | # 剔除开1的数据 |
| | | if timestamp_start <= int(k[2]) < timestamp_end: |
| | | continue |
| | | # 剔除高位板 |
| | | if _code in yesterday_limit_up_codes: |
| | | continue |
| | | # 代码.涨停时间 |
| | | block_codes_infos.append((_code, int(k[2]))) |
| | | block_codes_infos.append((code, limit_up_time)) |
| | | block_codes_infos.sort(key=lambda x: x[1]) |
| | | before_codes_info = [] |
| | | for i in range(0, len(block_codes_infos)): |
| | | if block_codes_infos[i][0] == code: |
| | | current_index = i |
| | | break |
| | | else: |
| | | before_codes_info.append(block_codes_infos[i]) |
| | | |
| | | return current_index, before_codes_info |
| | | |
| | | @classmethod |
| | | def __get_history_index(cls, code, block, yesterday_limit_up_codes, exclude_codes=None): |
| | | """ |
| | | 获取历史涨停身位 |
| | | @param code: |
| | | @param block: |
| | | @param current_limit_up_datas: 昨日涨停代码 |
| | | @param current_limit_up_codes: 目前的涨停代码 |
| | | @return: |
| | | """ |
| | | if exclude_codes is None: |
| | | exclude_codes = set() |
| | | history_index = 0 |
| | | block_codes_infos = [] |
| | | # 开1时间范围 |
| | | timestamp_start, timestamp_end = kpl_block_util.open_limit_up_time_range |
| | | limit_up_time = time.time() |
| | | limit_up_space_ge_60s_codes = set() |
| | | for k in LimitUpDataConstant.history_limit_up_datas: |
| | | _code = k[3] |
| | | |
| | | # 剔除4板以上的板 |
| | | if kpl_util.get_high_level_count(k[12]) >= 4: |
| | | continue |
| | | |
| | | if _code in exclude_codes: |
| | | continue |
| | | blocks = LimitUpDataConstant.get_blocks_with_history(_code) |
| | | blocks = BlockMapManager().filter_blocks(blocks) |
| | | if _code == code: |
| | | # 获取当前代码涨停时间 |
| | | limit_up_time = int(k[5]) |
| | | continue |
| | | # 不是这个板块 |
| | | if block not in blocks: |
| | | continue |
| | | if not tool.is_can_buy_code(_code): |
| | | continue |
| | | # 剔除开1的数据 |
| | | if timestamp_start <= int(k[5]) < timestamp_end: |
| | | continue |
| | | # 剔除高位板 |
| | | if _code in yesterday_limit_up_codes: |
| | | continue |
| | | # 剔除炸板代码持续涨停时间小于1分钟的代码 且 只能用于不排除前2条数据 |
| | | if _code not in cls.__current_limit_up_codes and _code in cls.__total_limit_up_space_dict and \ |
| | | cls.__total_limit_up_space_dict[_code] < 60 and not exclude_codes and len( |
| | | limit_up_space_ge_60s_codes) < 3: |
| | | limit_up_space_ge_60s_codes.add(_code) |
| | | continue |
| | | # 代码,涨停时间 |
| | | block_codes_infos.append((_code, int(k[5]))) |
| | | block_codes_infos.append((code, limit_up_time)) |
| | | block_codes_infos.sort(key=lambda x: x[1]) |
| | | before_codes_info = [] |
| | | for i in range(0, len(block_codes_infos)): |
| | | if block_codes_infos[i][0] == code: |
| | | history_index = i |
| | | break |
| | | else: |
| | | before_codes_info.append(block_codes_infos[i]) |
| | | return history_index, before_codes_info |
| | | |
| | | @classmethod |
| | | def __is_radical_buy_with_open_limitup(cls, code, block, yesterday_limit_up_codes): |
| | | """ |
| | | 是否需要激进买(某个板块开1) |
| | | 1.有>=2个开1买老2 |
| | | 2.有1个开1的买老3 |
| | | @param code: |
| | | @param block: |
| | | @param yesterday_limit_up_codes 昨日涨停代码 |
| | | @return: |
| | | """ |
| | | # 9:45点之前涨停的才能买入 |
| | | # 获取当前代码的涨停时间 |
| | | limit_up_timestamp = cls.__get_limit_up_timestamp(code) |
| | | if int(tool.timestamp_format(limit_up_timestamp, "%H%M%S")) > 94500: |
| | | return False, "超过生效时间" |
| | | # 根据板块聚合数据 |
| | | open_limit_up_block_codes_dict = {} |
| | | for c in kpl_data_constant.open_limit_up_code_dict_for_radical_buy: |
| | | blocks = kpl_data_constant.open_limit_up_code_dict_for_radical_buy[c][1] |
| | | for b in blocks: |
| | | if b not in open_limit_up_block_codes_dict: |
| | | open_limit_up_block_codes_dict[b] = set() |
| | | open_limit_up_block_codes_dict[b].add(c) |
| | | if block not in open_limit_up_block_codes_dict: |
| | | return False, "板块未开1" |
| | | open_limit_up_block_codes = list(open_limit_up_block_codes_dict.get(block)) |
| | | count = len(open_limit_up_block_codes) |
| | | # ----获取历史身位---- |
| | | history_index, history_before_codes_info = cls.__get_history_index(code, block, yesterday_limit_up_codes) |
| | | # ----获取实时身位---- |
| | | current_index, current_before_codes_info = cls.__get_current_index(code, block, yesterday_limit_up_codes, |
| | | limit_up_time=limit_up_timestamp) |
| | | exclude_codes = set() |
| | | if count >= 2 or ( |
| | | count == 1 and kpl_data_constant.open_limit_up_code_dict_for_radical_buy[open_limit_up_block_codes[0]][ |
| | | 0] == 2): |
| | | # 开始数量大于2个或者只有一个2板开1 |
| | | exclude_codes.clear() |
| | | else: |
| | | # 获取包含高位板的身位 |
| | | # ----获取历史身位---- |
| | | history_index, history_before_codes_info = cls.__get_history_index(code, block, set()) |
| | | # ----获取实时身位---- |
| | | current_index, current_before_codes_info = cls.__get_current_index(code, block, set(), |
| | | limit_up_time=limit_up_timestamp) |
| | | if history_before_codes_info and current_before_codes_info and history_before_codes_info[0][0] == \ |
| | | current_before_codes_info[0][0]: |
| | | # 前排第一个元素无炸板 |
| | | exclude_codes = {history_before_codes_info[0][0]} |
| | | else: |
| | | return False, f"开1数量:{count},历史-{history_index + 1} 实时-{current_index + 1}" |
| | | |
| | | # 获取主板的身位 |
| | | history_index, history_before_codes_info = cls.__get_history_index(code, block, |
| | | yesterday_limit_up_codes, |
| | | exclude_codes=exclude_codes) |
| | | # 过滤不正的原因 |
| | | history_index, history_before_codes_info = cls.__filter_before_codes(block, history_index, history_before_codes_info, yesterday_limit_up_codes) |
| | | |
| | | # 买首板老大/老二 |
| | | # 首板老大不能买时可买老二 |
| | | if history_index > 1: |
| | | return False, f"开1数量:{count},非开1首板身位不匹配:历史-{history_index + 1} 实时-{current_index + 1}" |
| | | if history_index == 1: |
| | | # 当前代码为老2,要判断老大是否可买 |
| | | if RedicalBuyDataManager.can_buy(history_before_codes_info[0][0], |
| | | DealAndDelegateWithBuyModeDataManager().get_deal_codes())[0]: |
| | | return False, f"开1数量:{count},前排代码可买:{history_before_codes_info[0]}" |
| | | return True, f"开1数量:{count},前排代码不可买:{history_before_codes_info[0]},历史前排-{history_before_codes_info},开1代码-{open_limit_up_block_codes}" |
| | | return True, f"开1数量:{count},历史-{history_index + 1} 实时-{current_index + 1}, 前排代码-{current_before_codes_info}, 开1代码-{open_limit_up_block_codes}" |
| | | |
| | | @classmethod |
| | | def __filter_before_codes(cls, block, index, before_codes_info, yesterday_codes): |
| | | """ |
| | | 过滤前排涨停原因不正的代码 |
| | | @param code: |
| | | @param block:板块 |
| | | @param index: 目标代码位置 |
| | | @param before_codes_info: [(代码, 涨停时间戳)] |
| | | @return: 过滤之后的 (index, before_codes_info) |
| | | """ |
| | | try: |
| | | if index == 0 or not before_codes_info: |
| | | return index, before_codes_info |
| | | temp_index = index |
| | | temp_before_codes_info = [] |
| | | for b in before_codes_info: |
| | | # 当作目标票获取扫入板块 |
| | | blocks = LimitUpCodesBlockRecordManager().get_radical_buy_blocks(b[0]) |
| | | blocks = BlockMapManager().filter_blocks(blocks) |
| | | if block not in blocks and b[0] not in yesterday_codes: |
| | | # 首板涨停原因不正 |
| | | temp_index -= 1 |
| | | else: |
| | | temp_before_codes_info.append(b) |
| | | |
| | | return temp_index, temp_before_codes_info |
| | | except Exception as e: |
| | | async_log_util.error(logger_debug, f"扫入板块过滤出错:{str(e)}") |
| | | return index, before_codes_info |
| | | |
| | | @classmethod |
| | | def __is_radical_buy_with_block_up(cls, code, block, yesterday_limit_up_codes): |
| | | """ |
| | | 是否激进买(板块突然涨起来) |
| | | 1.老二和老三的涨停时间相差5分钟内 |
| | | 2.老三不能买顺位到老四(老四与老三相差10分钟内) |
| | | 3.前2个票不能炸板(历史身位与现在身位一致) |
| | | 4.除开前两个代码可买老1与老2 |
| | | 5.买老2的情况:老1不满足买入条件 |
| | | |
| | | @param code: |
| | | @param block: |
| | | @param yesterday_limit_up_codes: |
| | | @return: |
| | | """ |
| | | |
| | | # 获取当前代码的涨停时间 |
| | | limit_up_timestamp = cls.__get_limit_up_timestamp(code) |
| | | |
| | | # 获取当前的板块 |
| | | current_index, current_before_codes_info = cls.__get_current_index(code, block, set(), |
| | | limit_up_time=limit_up_timestamp) |
| | | current_before_codes = [x[0] for x in current_before_codes_info] |
| | | |
| | | if len(current_before_codes_info) < 2: |
| | | return False, f"前排代码小于2个:{current_before_codes_info}" |
| | | |
| | | # 当前代码开1不能买 |
| | | if limit_up_timestamp < kpl_block_util.open_limit_up_time_range[1]: |
| | | return False, f"当前代码开1" |
| | | |
| | | if tool.trade_time_sub(tool.timestamp_format(limit_up_timestamp, '%H:%M:%S'), |
| | | tool.timestamp_format(current_before_codes_info[-1][1], '%H:%M:%S')) >= 10 * 60: |
| | | return False, f"距离上个代码涨停已过去10分钟({current_before_codes_info[0]})" |
| | | |
| | | history_index, history_before_codes_info = cls.__get_history_index(code, block, set()) |
| | | history_before_codes = [x[0] for x in history_before_codes_info] |
| | | # 前两个代码是否有炸板 |
| | | dif_codes = set(history_before_codes[:2]) - set(current_before_codes[:2]) |
| | | if dif_codes: |
| | | return False, f"前2代码有炸板:{dif_codes}" |
| | | # 不计算前2的代码 |
| | | |
| | | exclude_codes = set() |
| | | for x in current_before_codes_info: |
| | | if x[1] < kpl_block_util.open_limit_up_time_range[1]: |
| | | exclude_codes.add(x[0]) |
| | | # 除去前二代码与开1代码之后是否为首板老大:所有开1的视为1个 |
| | | open_count = len(exclude_codes) |
| | | if open_count > 0 and open_count + 1 <= len(current_before_codes): |
| | | # 前排有开1 |
| | | exclude_codes |= set(current_before_codes[open_count:open_count + 1]) |
| | | else: |
| | | exclude_codes |= set(current_before_codes[:2]) |
| | | |
| | | open_limit_up_code_dict = kpl_data_constant.open_limit_up_code_dict_for_radical_buy |
| | | if open_limit_up_code_dict: |
| | | exclude_codes |= set(open_limit_up_code_dict.keys()) |
| | | history_index, history_before_codes_info = cls.__get_history_index(code, block, yesterday_limit_up_codes, |
| | | exclude_codes) |
| | | |
| | | # 过滤不正的原因 |
| | | history_index, history_before_codes_info = cls.__filter_before_codes(block, history_index, |
| | | history_before_codes_info, |
| | | yesterday_limit_up_codes) |
| | | |
| | | # 获取本板块买入代码的最大数量 |
| | | max_count = RadicalBuyBlockCodeCountManager().get_block_code_count(block) |
| | | if history_index > max_count: |
| | | return False, f"排除前2,目标代码位于历史身位-{history_index + 1},前排代码:{history_before_codes_info}, 板块最多可买{max_count}" |
| | | |
| | | if max_count == 1: |
| | | if history_index == 1: |
| | | # 首板老2,判断前面的老大是否是属于不能买的范畴 |
| | | pre_code = history_before_codes_info[0][0] |
| | | # pre_code不能买,才能买 |
| | | if RedicalBuyDataManager.can_buy(pre_code, DealAndDelegateWithBuyModeDataManager().get_deal_codes())[0]: |
| | | return False, f"前排代码可买:{pre_code}" |
| | | # 距离前一个是否在10分钟内 |
| | | if tool.trade_time_sub(tool.timestamp_format(limit_up_timestamp, '%H:%M:%S'), |
| | | tool.timestamp_format(history_before_codes_info[-1][1], '%H:%M:%S')) >= 10 * 60: |
| | | return False, f"距离上个不能买的代码涨停已过去10分钟({history_before_codes_info[0]})" |
| | | else: |
| | | # 距离上个代码涨停5分钟以内 |
| | | if tool.trade_time_sub(tool.timestamp_format(limit_up_timestamp, '%H:%M:%S'), |
| | | tool.timestamp_format(current_before_codes_info[-1][1], '%H:%M:%S')) >= 10 * 60: |
| | | return False, f"距离上个代码涨停已过去10分钟({current_before_codes_info[-1]})" |
| | | else: |
| | | if tool.trade_time_sub(tool.timestamp_format(limit_up_timestamp, '%H:%M:%S'), |
| | | tool.timestamp_format(current_before_codes_info[-1][1], '%H:%M:%S')) >= 10 * 60: |
| | | return False, f"距离上个代码涨停已过去10分钟({current_before_codes_info[-1]})" |
| | | |
| | | return True, f"满足买入需求: 前排代码-{current_before_codes_info}" |
| | | |
| | | @classmethod |
| | | def __is_re_limit_up(cls, code, block): |
| | | """ |
| | | 是否是炸板回封可买 |
| | | @param code: |
| | | @param block: |
| | | @return: |
| | | """ |
| | | # 获取身位 |
| | | current_index, current_before_codes_info = cls.__get_current_index(code, block, set(), |
| | | limit_up_time=cls.__get_limit_up_timestamp( |
| | | code)) |
| | | history_index, history_before_codes_info = cls.__get_history_index(code, block, set()) |
| | | if current_index != history_index: |
| | | return False, f"有其他炸板" |
| | | if current_index > 1: |
| | | return False, f"不是前2的板块" |
| | | history_codes = set() |
| | | # 获取板块炸板情况 |
| | | for k in LimitUpDataConstant.history_limit_up_datas: |
| | | _code = k[3] |
| | | blocks = LimitUpDataConstant.get_blocks_with_history(_code) |
| | | blocks = BlockMapManager().filter_blocks(blocks) |
| | | # 不是这个板块 |
| | | if block in blocks: |
| | | history_codes.add(_code) |
| | | if len(history_codes) <= 4: |
| | | return False, f"板块历史涨停小于4个:{history_codes}" |
| | | # 获取当前涨停数量 |
| | | current_codes = set() |
| | | for k in LimitUpDataConstant.current_limit_up_datas: |
| | | _code = k[0] |
| | | blocks = LimitUpDataConstant.get_blocks_with_history(_code) |
| | | if not blocks: |
| | | blocks = set() |
| | | blocks = BlockMapManager().filter_blocks(blocks) |
| | | # 不是这个板块 |
| | | if block in blocks: |
| | | current_codes.add(_code) |
| | | current_codes.add(code) |
| | | diff = history_codes - current_codes |
| | | if diff: |
| | | return False, f"板块炸板不止当前票:{diff}" |
| | | return True, "" |
| | | |
| | | @classmethod |
| | | def __get_limit_up_timestamp(cls, code): |
| | | """ |
| | | 获取代码的涨停时间,默认当前时间 |
| | | @param code: |
| | | @return: |
| | | """ |
| | | limit_up_timestamp = LimitUpDataConstant.get_first_limit_up_time(code) |
| | | if not limit_up_timestamp: |
| | | limit_up_timestamp = time.time() |
| | | return limit_up_timestamp |
| | | |
| | | @classmethod |
| | | def get_code_kpl_blocks(cls, code): |
| | | blocks = KPLCodeJXBlockManager().get_jx_blocks_radical(code) |
| | | if blocks is None: |
| | | blocks = set() |
| | | # 将获取涨停原因与涨停推荐 |
| | | keys = TargetCodePlateKeyManager().get_plate_keys(code, contains_today=True) |
| | | if keys and keys[0]: |
| | | blocks |= set(keys[0]) |
| | | return blocks |
| | | |
| | | @classmethod |
| | | def get_code_blocks(cls, code): |
| | | """ |
| | | 获取目标代码的板块 |
| | | @param code: |
| | | @return: 过滤后的板块,过滤前的板块 |
| | | """ |
| | | # blocks = cls.get_code_kpl_blocks(code) |
| | | # match_blocks, info = CodeThirdBlocksManager().get_intersection_blocks_info(code, blocks) |
| | | # match_blocks -= constant.KPL_INVALID_BLOCKS |
| | | # fblocks = match_blocks & RealTimeKplMarketData.get_top_market_jingxuan_blocks() |
| | | # if not fblocks: |
| | | # fblocks = set() |
| | | # match_blocks_3, info = CodeThirdBlocksManager().get_intersection_blocks_info(code, blocks, same_count=3) |
| | | # if match_blocks_3: |
| | | # match_blocks_3 -= constant.KPL_INVALID_BLOCKS |
| | | # fblocks |= match_blocks_3 |
| | | # # 获取开盘啦历史涨停原因 |
| | | # kpl_history_blocks = CodesHisReasonAndBlocksManager().get_history_blocks_cache(code) |
| | | # if kpl_history_blocks: |
| | | # fblocks |= BlockMapManager().filter_blocks(kpl_history_blocks) |
| | | # jx_out_blocks = RealTimeKplMarketData.get_top_market_jingxuan_out_blocks() |
| | | # if jx_out_blocks: |
| | | # fblocks -= jx_out_blocks |
| | | # |
| | | # return fblocks, match_blocks |
| | | |
| | | # 新版本 |
| | | before_fblocks = LimitUpCodesBlockRecordManager().get_radical_buy_blocks(code) |
| | | if not before_fblocks: |
| | | before_fblocks = set() |
| | | fblocks = BlockMapManager().filter_blocks(before_fblocks) |
| | | if fblocks: |
| | | fblocks -= constant.KPL_INVALID_BLOCKS |
| | | return fblocks, before_fblocks |
| | | |
| | | @classmethod |
| | | def is_radical_buy(cls, code, yesterday_limit_up_codes): |
| | | """ |
| | | 是否是激进买 |
| | | @param code: |
| | | @return: {激进买的板块}, 原因 |
| | | """ |
| | | # 计算 |
| | | # 获取开1的板块 |
| | | open_limit_up_code_dict = kpl_data_constant.open_limit_up_code_dict_for_radical_buy |
| | | open_limit_up_blocks = set() |
| | | if open_limit_up_code_dict: |
| | | for c in open_limit_up_code_dict: |
| | | open_limit_up_blocks |= open_limit_up_code_dict[c][1] |
| | | # 获取代码的板块 |
| | | keys_, info = cls.get_code_blocks(code) |
| | | if not keys_: |
| | | return set(), "没获取到板块交集" |
| | | |
| | | match_blocks = open_limit_up_blocks & keys_ |
| | | can_buy_blocks = set() |
| | | fmsges = [] |
| | | msges = [] |
| | | for b in match_blocks: |
| | | # 判断板块是否该激进买 |
| | | result = cls.__is_radical_buy_with_open_limitup(code, b, yesterday_limit_up_codes) |
| | | if result[0]: |
| | | can_buy_blocks.add(b) |
| | | msges.append(f"【{b}】:{result[1]}") |
| | | fmsges.append("开1判断##" + ",".join(msges)) |
| | | if not can_buy_blocks: |
| | | msges.clear() |
| | | for b in keys_: |
| | | # 板块快速启动 |
| | | result = cls.__is_radical_buy_with_block_up(code, b, yesterday_limit_up_codes) |
| | | if result[0]: |
| | | can_buy_blocks.add(b) |
| | | |
| | | msges.append(f"【{b}】:{result[1]}") |
| | | fmsges.append("板块快速启动判断##" + ",".join(msges)) |
| | | |
| | | if not can_buy_blocks: |
| | | msges.clear() |
| | | for b in keys_: |
| | | result = cls.__is_re_limit_up(code, b) |
| | | if result[0]: |
| | | can_buy_blocks.add(b) |
| | | msges.append(f"【{b}】:{result[1]}") |
| | | fmsges.append("板块回封判断##" + ",".join(msges)) |
| | | |
| | | # 如果能扫入就需要获取代码在板块中的身位 |
| | | # if can_buy_blocks: |
| | | # excude_codes = set() |
| | | # if kpl_data_constant.open_limit_up_code_dict_for_radical_buy: |
| | | # excude_codes |= kpl_data_constant.open_limit_up_code_dict_for_radical_buy.keys() |
| | | # # 剔除开1的代码 |
| | | # for b in keys_: |
| | | # history_index, history_before_codes_info = cls.__get_history_index(code, b, yesterday_limit_up_codes, |
| | | # excude_codes) |
| | | # if history_index >= 4: |
| | | # return set(), f"在【{b}】中身位({history_index + 1})靠后" |
| | | return can_buy_blocks, " **** ".join(fmsges) |
| | | |
| | | |
| | | if __name__ == "__main__": |
| | | pass |
| | | KPLPlateForbiddenManager().compute() |