From 283a7c89f85b1584fde8ff429028506dc00e53d7 Mon Sep 17 00:00:00 2001 From: Administrator <admin@example.com> Date: 星期二, 08 七月 2025 14:17:47 +0800 Subject: [PATCH] bug修复/策略完善 --- strategy/time_series_backtest.py | 1063 +++++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 705 insertions(+), 358 deletions(-) diff --git a/strategy/time_series_backtest.py b/strategy/time_series_backtest.py index d9f007a..4a14f4c 100644 --- a/strategy/time_series_backtest.py +++ b/strategy/time_series_backtest.py @@ -1,19 +1,21 @@ +import logging + import constant from code_attribute import gpcode_manager, code_nature_analyse -from strategy.data_analyzer import KPLLimitUpDataAnalyzer -from strategy.data_downloader import DataDownloader -from strategy.low_suction_strategy import LowSuctionOriginDataExportManager -from strategy.strategy_params_settings import StrategyParamsSettings, StrategyParamsSettingsManager +from strategy.data.data_analyzer import KPLLimitUpDataAnalyzer +from strategy.data.data_downloader import DataDownloader +from strategy.data.data_manager import LowSuctionOriginDataExportManager +from strategy.strategy_params_settings import StrategyParamsSettingsManager from strategy.strategy_variable import StockVariables from strategy.strategy_variable_factory import DataLoader, StrategyVariableFactory from third_data import kpl_util -from third_data.third_blocks_manager import BlockMapManager from utils import tool, huaxin_util class BackTest: - def __init__(self, day, script_name="浣庡惛鑴氭湰_杈ㄨ瘑搴v3.py", settings=StrategyParamsSettingsManager().get_settings()): + def __init__(self, day, script_name="浣庡惛鑴氭湰_杈ㄨ瘑搴v3.py", settings=StrategyParamsSettingsManager().get_settings(), + target_codes=set()): self.day = day scripts = "" with open(script_name, mode='r', encoding='utf-8') as f: @@ -26,7 +28,7 @@ self.settings = settings self.scripts = scripts self.RANGE_TIMES = ("09:25:00", "11:30:00") - self.current_time = '09:25:00' + self.current_time = self.RANGE_TIMES[0] self.stock_variables_dict = {} self.data_loader: DataLoader = None @@ -40,6 +42,9 @@ self.deal_codes = set() # 鏉垮潡宸茬粡鎴愪氦鐨勪唬鐮� self.deal_block_codes = {} + self.target_codes = target_codes + self.backtest_results = [] + self.finish = False def set_script(self, script): self.scripts = script @@ -120,15 +125,16 @@ :return: 鎸夋椂闂存帓搴忕殑鏁版嵁鍒楄〃 """ if self.day >= '2025-05-26': - IS_BY_BIG_ORDER = True - else: IS_BY_BIG_ORDER = False + else: + IS_BY_BIG_ORDER = True day = self.day fdata = {} __LowSuctionOriginDataExportManager = LowSuctionOriginDataExportManager(day) all_limit_up_list = __LowSuctionOriginDataExportManager.export_limit_up_list() fdata["limit_up_list"] = {d[0][:8]: d[1] for d in all_limit_up_list} - big_order_deals = __LowSuctionOriginDataExportManager.export_big_order_deal(BIG_ORDER_MONEY_THRESHOLD) + big_order_deals = __LowSuctionOriginDataExportManager.export_big_order_deal(BIG_ORDER_MONEY_THRESHOLD, + max_deal_space=3) if not big_order_deals or IS_BY_BIG_ORDER: big_order_deals = __LowSuctionOriginDataExportManager.export_big_order_deal_by(BIG_ORDER_MONEY_THRESHOLD) # 杞崲鏍煎紡涓猴細{鏃堕棿: [("浠g爜", (涔板崟鍙�, 閲�, 閲戦, 鏃堕棿, 鏈�缁堟垚浜や环))] @@ -170,7 +176,8 @@ code_plates_dict_for_refer = self.data_loader.load_code_plates_for_refer() - plate_codes = self.data_loader.load_target_plate_and_codes() + # TODO 蹇�熸媺浼搁┍鍔� + plate_codes = self.data_loader.load_target_plate_and_codes_v2() code_plates_dict_for_buy = {} for p in plate_codes: for code in plate_codes.get(p): @@ -248,43 +255,6 @@ exec(self.scripts, global_dict) return global_dict["compute_result"] - def __filter_codes(self, current_data, timeline_data): - code_plates = current_data["code_plates"] - start_time, end_time = self.RANGE_TIMES[0], self.RANGE_TIMES[1] - fplates = set() - for i in range(60 * 60 * 5): - time_str = tool.trade_time_add_second(start_time, i) - if time_str > end_time: - break - self.current_time = time_str - # 缁熻褰撳墠娑ㄥ仠鏁版嵁 - current_limit_up_list = current_data["limit_up_list"].get(time_str) - if current_limit_up_list: - # 缁熻鏉垮潡娑ㄥ仠 - plate_codes_info = {} - for x in current_limit_up_list: - plates = code_plates.get(x[0]) - if plates: - for p in plates: - if p not in plate_codes_info: - plate_codes_info[p] = [] - plate_codes_info[p].append((x[0], x[2])) - # print(time_str, "姹借溅闆堕儴浠�", plate_codes_info.get("姹借溅闆堕儴浠�")) - # 鏈夋晥鐨勬澘鍧� - valid_plates = set([p for p in plate_codes_info if len(plate_codes_info[p]) >= 2]) - fplates |= valid_plates - codes = set([code for code in code_plates if code_plates[code] & fplates]) - fcodes = set() - for c in codes: - if c not in timeline_data["kline_data"]: - continue - # 鑷敱娴侀�氬競鍊�30-300浜� - pre_close = timeline_data["kline_data"].get(c)[0]["close"] - if 30e8 <= current_data["zylt_volume"].get(c) * pre_close <= 300e8: - fcodes.add(c) - - return fcodes - def __get_target_codes_v4(self): valid_codes = self.timeline_data["valid_codes"] return set(self.current_data["code_plates_for_buy"].keys()) & valid_codes @@ -297,6 +267,9 @@ """ if code_ in self.stock_variables_dict: return + + if code_ == '002907': + print("") stock_variables = StrategyVariableFactory.create_from_history_data( timeline_data["kline_data"].get(code_), timeline_data["minute_data"].get(code_), @@ -316,8 +289,6 @@ stock_variables.鏂颁唬鐮佹澘鍧� = timeline_data["code_blocks"].get(code_) stock_variables.杈ㄨ瘑搴︿唬鐮� = self.fcodes stock_variables.棰嗘定鏉垮潡淇℃伅 = self.head_rise_code_blocks.get(code_) - if code_ in DEBUG_CODES: - print(code_, stock_variables.棰嗘定鏉垮潡淇℃伅) for day in [2, 5, 10, 30, 60, 120]: days = timeline_data["trade_days"][:day] @@ -327,7 +298,7 @@ max_day=days[0])) stock_variables.杩炵画鑰侀鏉� = KPLLimitUpDataAnalyzer.get_continuous_limit_up_reasons( timeline_data["limit_up_record_data_list"], self.data_loader.trade_days[:2]) - + stock_variables.杩炵画鑰侀鏉�.clear() self.stock_variables_dict[code_] = stock_variables def load_data(self): @@ -353,7 +324,7 @@ # self.fcodes, self.head_rise_code_blocks = self.__get_target_codes_v3() # __filter_codes(current_data, timeline_data) self.fcodes, self.head_rise_code_blocks = self.__get_target_codes_v4(), {} - print(len(self.fcodes), self.fcodes) + print(len(self.fcodes)) if not self.current_tick_data: try: self.current_tick_data = self.load_current_tick_datas(self.data_loader) @@ -411,363 +382,731 @@ return ";".join([f"{x[0]}==鍑�棰�:{x[1]},涔板崟锛歿x[2]},鍗栧崟锛歿x[3]}" for x in infos]) def run(self): - self.load_data() - # print(self.fcodes) - limit_up_record_data_dict = {} - for limit_up_item in self.timeline_data["limit_up_record_data"]: - if limit_up_item[0] not in limit_up_record_data_dict: - limit_up_record_data_dict[limit_up_item[0]] = [] - limit_up_record_data_dict[limit_up_item[0]].append(limit_up_item) - self.timeline_data["limit_up_record_data"] = limit_up_record_data_dict - next_trade_day = self.timeline_data["next_trade_day"] - start_time, end_time = "09:25:00", "12:00:00" - # 鍒嗛挓K绾� - minute_bars_dict = {} - code_plates = self.current_data["code_plates"] - code_plates_for_refer = self.current_data["code_plates_for_refer"] + try: + self.load_data() + # print(self.fcodes) + limit_up_record_data_dict = {} + for limit_up_item in self.timeline_data["limit_up_record_data"]: + if limit_up_item[0] not in limit_up_record_data_dict: + limit_up_record_data_dict[limit_up_item[0]] = [] + limit_up_record_data_dict[limit_up_item[0]].append(limit_up_item) + self.timeline_data["limit_up_record_data"] = limit_up_record_data_dict + next_trade_day = self.timeline_data["next_trade_day"] + start_time, end_time = "09:25:00", "12:00:00" + # 鍒嗛挓K绾� + minute_bars_dict = {} + code_plates = self.current_data["code_plates"] + code_plates_for_refer = self.current_data["code_plates_for_refer"] - # 鏉垮潡娑ㄥ仠浠g爜淇℃伅 - kpl_plate_limit_up_codes_info = None - plate_limit_up_codes_info = None - kpl_head_plate_limit_up_codes_info = None + # 鏉垮潡娑ㄥ仠浠g爜淇℃伅 + kpl_plate_limit_up_codes_info = None + plate_limit_up_codes_info = None + kpl_head_plate_limit_up_codes_info = None - latest_current_limit_up_list = None + latest_current_limit_up_list = None - latest_block_in_datas = None + latest_block_in_datas = None - # 鏍规嵁鏉垮潡鑾峰彇鐩爣绁� - target_plate_codes_infos = {} - for code in self.head_rise_code_blocks: - for p in self.head_rise_code_blocks[code]: - if p not in target_plate_codes_infos: - target_plate_codes_infos[p] = [] - target_plate_codes_infos[p].append(self.head_rise_code_blocks[code][p]) - for p in target_plate_codes_infos: - target_plate_codes_infos[p].sort(key=lambda x: x[1], reverse=True) + # 鏍规嵁鏉垮潡鑾峰彇鐩爣绁� + target_plate_codes_infos = {} + for code in self.head_rise_code_blocks: + for p in self.head_rise_code_blocks[code]: + if p not in target_plate_codes_infos: + target_plate_codes_infos[p] = [] + target_plate_codes_infos[p].append(self.head_rise_code_blocks[code][p]) + for p in target_plate_codes_infos: + target_plate_codes_infos[p].sort(key=lambda x: x[1], reverse=True) - all_new_plates = set() + all_new_plates = set() - for i in range(60 * 60 * 5): - time_str = tool.trade_time_add_second(start_time, i) - # print(f"[{tool.get_now_time_str()}]", time_str) - if time_str > end_time: - break - ticks = self.current_tick_data.get(time_str) if self.current_tick_data else None - # ===============缁熻褰撳墠娑ㄥ仠鏁版嵁 - origin_current_limit_up_list = self.current_data["limit_up_list"].get(time_str, []) - current_limit_up_list = [x for x in origin_current_limit_up_list if kpl_util.get_high_level_count(x[4]) < 3] + for i in range(60 * 60 * 5): + if self.finish: + break + time_str = tool.trade_time_add_second(start_time, i) + # print(f"[{tool.get_now_time_str()}]", time_str) + if time_str > end_time: + break + self.current_time = time_str + ticks = self.current_tick_data.get(time_str) if self.current_tick_data else None + # ===============缁熻褰撳墠娑ㄥ仠鏁版嵁 + origin_current_limit_up_list = self.current_data["limit_up_list"].get(time_str, []) + current_limit_up_list = [x for x in origin_current_limit_up_list if + kpl_util.get_high_level_count(x[4]) < 3] - if current_limit_up_list: - latest_current_limit_up_list = current_limit_up_list + if current_limit_up_list: + latest_current_limit_up_list = current_limit_up_list - if current_limit_up_list: - plate_codes_info = {} - # 缁熻鏉垮潡娑ㄥ仠 - for x in current_limit_up_list: - # 鎸変唬鐮佺殑鏉垮潡缁熻娑ㄥ仠鏉垮潡涓殑浠g爜鏁伴噺 - # 娑ㄥ仠杩�1鍒嗛挓鎵嶇畻鏈夋晥娑ㄥ仠 - if tool.trade_time_sub(time_str, tool.timestamp_format(x[2], "%H:%M:%S")) < 60: - continue - plates = code_plates.get(x[0]) - if plates: + if current_limit_up_list: + plate_codes_info = {} + # 缁熻鏉垮潡娑ㄥ仠 + for x in current_limit_up_list: + # 鎸変唬鐮佺殑鏉垮潡缁熻娑ㄥ仠鏉垮潡涓殑浠g爜鏁伴噺 + # 娑ㄥ仠杩�1鍒嗛挓鎵嶇畻鏈夋晥娑ㄥ仠 + if tool.trade_time_sub(time_str, tool.timestamp_format(x[2], "%H:%M:%S")) < 60: + continue + plates = code_plates.get(x[0]) + if plates: + for p in plates: + if p not in plate_codes_info: + plate_codes_info[p] = [] + plate_codes_info[p].append((x[0], x[2])) + plate_limit_up_codes_info = plate_codes_info + + plate_codes_info = {} + for x in current_limit_up_list: + # 鎸夊紑鐩樺暒娑ㄥ仠鍘熷洜缁熻 + p = x[5] + if p in constant.KPL_INVALID_BLOCKS: + continue + if p not in plate_codes_info: + plate_codes_info[p] = [] + # 濡傛灉棰嗘定浠g爜閲岄潰娌℃湁褰撳墠绁ㄥ氨涓嶇畻杩欎釜鏉垮潡鐨勬定鍋滃師鍥� + # 鑾峰彇棰嗘定鏁版嵁 + # head_plate_codes_info = self.data_loader.load_plate_codes(x[9], p) + # if head_plate_codes_info: + # plate_codes = set([x[0] for x in head_plate_codes_info]) + # else: + # plate_codes = set() + # if x[0] not in plate_codes: + # continue + plate_codes_info[p].append((x[0], x[2], x[4])) + kpl_plate_limit_up_codes_info = plate_codes_info + + # {"浠g爜":[(鏉垮潡浠g爜, 鏉垮潡鍚嶇О)]} + limit_up_plate_names_of_refer_code = self.current_data["limit_up_plate_names_of_refer_code"] + plate_codes_info = {} + for x in current_limit_up_list: + # 鎸夊紑鐩樺暒娑ㄥ仠鍘熷洜缁熻 + code = x[0] + # if code not in limit_up_plate_names_of_refer_code: + # continue + # 濡傛灉璁板綍娑ㄥ仠鏃堕棿杩囧幓20鍒嗛挓灏遍噰鐢ㄦ定鍋滈槦鍒楃殑娑ㄥ仠鍘熷洜 + if tool.trade_time_sub(time_str, tool.timestamp_format(x[2], "%H:%M:%S")) < 60 * 20 or True: + plates_infos = limit_up_plate_names_of_refer_code.get(code) + plates = set([d[1] for d in plates_infos if d[1] == x[5]]) if plates_infos else set() + else: + plates = {x[5]} + + new_plates = set() for p in plates: + if p in constant.KPL_INVALID_BLOCKS: + continue + new_plates.add(p) + for p in new_plates: if p not in plate_codes_info: plate_codes_info[p] = [] plate_codes_info[p].append((x[0], x[2])) - plate_limit_up_codes_info = plate_codes_info + kpl_head_plate_limit_up_codes_info = plate_codes_info - plate_codes_info = {} - for x in current_limit_up_list: - # 鎸夊紑鐩樺暒娑ㄥ仠鍘熷洜缁熻 - p = x[5] - if p in constant.KPL_INVALID_BLOCKS: - continue - if p not in plate_codes_info: - plate_codes_info[p] = [] - # 濡傛灉棰嗘定浠g爜閲岄潰娌℃湁褰撳墠绁ㄥ氨涓嶇畻杩欎釜鏉垮潡鐨勬定鍋滃師鍥� - # 鑾峰彇棰嗘定鏁版嵁 - # head_plate_codes_info = self.data_loader.load_plate_codes(x[9], p) - # if head_plate_codes_info: - # plate_codes = set([x[0] for x in head_plate_codes_info]) - # else: - # plate_codes = set() - # if x[0] not in plate_codes: - # continue - plate_codes_info[p].append((x[0], x[2], x[4])) - kpl_plate_limit_up_codes_info = plate_codes_info + # ==================娉ㄥ叆鏉垮潡娴佸叆 + block_in_datas = self.current_data["block_in"].get(time_str) + if block_in_datas: + blocks = [x[0] for x in block_in_datas if x[1] > 0] + block_in_datas = blocks[:20] + latest_block_in_datas = block_in_datas - # {"浠g爜":[(鏉垮潡浠g爜, 鏉垮潡鍚嶇О)]} - limit_up_plate_names_of_refer_code = self.current_data["limit_up_plate_names_of_refer_code"] - plate_codes_info = {} - for x in current_limit_up_list: - # 鎸夊紑鐩樺暒娑ㄥ仠鍘熷洜缁熻 - code = x[0] - # if code not in limit_up_plate_names_of_refer_code: - # continue - # 濡傛灉璁板綍娑ㄥ仠鏃堕棿杩囧幓20鍒嗛挓灏遍噰鐢ㄦ定鍋滈槦鍒楃殑娑ㄥ仠鍘熷洜 - if tool.trade_time_sub(time_str, tool.timestamp_format(x[2], "%H:%M:%S")) < 60 * 20 or True: - plates_infos = limit_up_plate_names_of_refer_code.get(code) - plates = set([d[1] for d in plates_infos if d[1] == x[5]]) if plates_infos else set() - else: - plates = {x[5]} + # ================褰撳墠鏃跺埢澶у崟 + current_big_orders = self.current_data["big_order"].get(time_str) + if current_big_orders: + for big_order in current_big_orders: + # 鏍煎紡 ("浠g爜", (涔板崟鍙�, 閲�, 閲戦, 鏃堕棿, 鏈�缁堟垚浜や环)) + self.init_stock_variables(big_order[0], self.timeline_data, self.current_data) + stock_variables: StockVariables = self.stock_variables_dict.get(big_order[0]) + if stock_variables.浠婃棩澶у崟鏁版嵁 is None: + stock_variables.浠婃棩澶у崟鏁版嵁 = [] + stock_variables.浠婃棩澶у崟鏁版嵁.append(big_order[1]) + # 缁熻澶у崟鍧囦环 + order_ids = set() + total_money = 0 + total_volume = 0 + for order in reversed(stock_variables.浠婃棩澶у崟鏁版嵁): + if order[0] in order_ids: + continue + order_ids.add(order[0]) + total_money += order[2] + total_volume += order[1] + if total_volume > 0: + stock_variables.浠婃棩澶у崟鍧囦环 = round(total_money / total_volume, 2) + else: + stock_variables.浠婃棩澶у崟鍧囦环 = 0 + current_big_sell_orders = self.current_data["big_sell_order"].get(time_str) + if current_big_sell_orders: + for big_order in current_big_sell_orders: + # 鏍煎紡 ("浠g爜", (涔板崟鍙�, 閲�, 閲戦, 鏃堕棿, 鏈�缁堟垚浜や环)) + self.init_stock_variables(big_order[0], self.timeline_data, self.current_data) + stock_variables: StockVariables = self.stock_variables_dict.get(big_order[0]) + if stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹� is None: + stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹� = [] + stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹�.append(big_order[1]) - new_plates = set() + # 寮�鐩樺暒鏈�姝f定鍋滃師鍥� + most_real_kpl_plate_limit_up_codes_info = {} + # 鑾峰彇杩欎釜鏉垮潡鐨勭洰鏍囩エ + if kpl_plate_limit_up_codes_info: + current_limit_up_dict = {x[0]: x for x in latest_current_limit_up_list} + codes = set() + for plate in kpl_plate_limit_up_codes_info: + kpl_plate_codes = kpl_plate_limit_up_codes_info.get(plate) + codes |= set([x[0] for x in kpl_plate_codes]) + for code in codes: + plates = code_plates.get(code) + if not plates: + plates = {current_limit_up_dict.get(code)[5]} + plates -= constant.KPL_INVALID_BLOCKS + if plates: + for p in plates: + if p not in most_real_kpl_plate_limit_up_codes_info: + most_real_kpl_plate_limit_up_codes_info[p] = [] + most_real_kpl_plate_limit_up_codes_info[p].append(code) + # print(time_str, "娑ㄥ仠鏁板ぇ浜�3涓�", [p for p in most_real_kpl_plate_limit_up_codes_info if + # len(most_real_kpl_plate_limit_up_codes_info[p]) >= 3]) + + # ---------娴嬭瘯-------- + # test_plate = "鍖栧伐" + # if len(most_real_kpl_plate_limit_up_codes_info.get(test_plate, [])) >= 3: + # print("娴嬭瘯寮�濮�=========") + # code_plates_for_buy = self.current_data["code_plates_for_buy"] + # plate_codes = [c for c in code_plates_for_buy if test_plate in code_plates_for_buy[c]] + # print(f"{test_plate}婊¤冻", time_str, plate_codes) + # for c in plate_codes: + # sv: StockVariables = self.stock_variables_dict.get(c) + # if sv and sv.褰撳墠浠� > sv.鏄ㄦ棩鏀剁洏浠�: + # print(c) + # print("娴嬭瘯瀹屾瘯=========") + + if ticks: + for tick in ticks: + code = tick["symbol"][-6:] + if code not in self.fcodes: + continue + if self.target_codes and code not in self.target_codes: + continue + + if code not in self.stock_variables_dict: + # 鍔犺浇鍩虹鏁版嵁 + self.init_stock_variables(code, self.timeline_data, self.current_data) + stock_variables: StockVariables = self.stock_variables_dict.get(code) + if plate_limit_up_codes_info is not None: + stock_variables.鏉垮潡娑ㄥ仠 = plate_limit_up_codes_info + + if kpl_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒鏉垮潡娑ㄥ仠 = kpl_plate_limit_up_codes_info + + if kpl_head_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒棰嗘定鏉垮潡娑ㄥ仠 = kpl_head_plate_limit_up_codes_info + + stock_variables.鏉垮潡鎴愪氦浠g爜 = self.deal_block_codes + # 鏉垮潡娴佸叆鏁版嵁 + if latest_block_in_datas: + stock_variables.璧勯噾娴佸叆鏉垮潡 = latest_block_in_datas + # 鏆傛椂涓嶇敤鍒嗛挓K绾� + # if code not in minute_bars_dict: + # minute_bars_dict[code] = [tick] + # if minute_bars_dict[code][-1]["created_at"][:-2] == tick["created_at"][:-2]: + # # 缁熻鍒嗛挓K绾� + # minute_bars_dict[code][-1] = tick + # else: + # # 淇濆瓨鍒嗛挓K绾挎渶楂樹环 + # if not stock_variables.浠婃棩鏈�楂樹环: + # stock_variables.浠婃棩鏈�楂樹环 = minute_bars_dict[code][-1]["price"] + # if minute_bars_dict[code][-1]["price"] > stock_variables.浠婃棩鏈�楂樹环: + # stock_variables.浠婃棩鏈�楂樹环 = minute_bars_dict[code][-1]["price"] + + # 淇濆瓨寮�鐩樹环 + if tick["created_at"][-8:] < '09:30:00': + stock_variables.浠婃棩寮�鐩樹环 = tick["price"] + # 浠婃棩寮�鐩樻定骞� + stock_variables.浠婃棩寮�鐩樻定骞� = round( + (tick["price"] - stock_variables.鏄ㄦ棩鏀剁洏浠�) / stock_variables.鏄ㄦ棩鏀剁洏浠�, + 4) + stock_variables.浠婃棩鎴愪氦閲� = tick["cum_volume"] + stock_variables.浠婃棩鎴愪氦棰� = tick["cum_amount"] + stock_variables.褰撳墠浠� = tick["price"] + if not stock_variables.浠婃棩閲忓淇℃伅: + if stock_variables.浠婃棩鎴愪氦閲� > stock_variables.鏄ㄦ棩鎴愪氦閲� * 0.8: + stock_variables.浠婃棩閲忓淇℃伅 = (time_str, stock_variables.褰撳墠浠�, round( + (stock_variables.褰撳墠浠� - stock_variables.鏄ㄦ棩鏀剁洏浠�) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2), + self.__statistic_big_order_info(stock_variables)) + if VOLUME_LOG_ENABLE: + # 缁熻澶у崟鍑�棰濓紝(50w浠ヤ笂,鍑�棰�,涔板崟涓暟/涔板崟鎬婚噾棰�,鍗栧崟涓暟/鍗栧崟鎬婚噾棰�) + print("****閲忓", code, stock_variables.浠婃棩閲忓淇℃伅) + + # 缁熻浠婃棩鏈�楂樹环 + # if stock_variables.浠婃棩鏈�楂樹环 and tick["price"] > stock_variables.浠婃棩鏈�楂樹环: + # print(code, "====绐佺牬鍒嗘椂鏈�楂樹环锛�", tick["created_at"], tick["price"]) + + if not stock_variables.浠婃棩鏈�楂樹环淇℃伅 or tick["price"] > stock_variables.浠婃棩鏈�楂樹环淇℃伅[0]: + stock_variables.浠婃棩鏈�楂樹环淇℃伅 = (tick["price"], time_str) + + if not stock_variables.浠婃棩鏈�浣庝环 or tick["price"] < stock_variables.浠婃棩鏈�浣庝环: + stock_variables.浠婃棩鏈�浣庝环 = tick["price"] + if most_real_kpl_plate_limit_up_codes_info: + stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋� = most_real_kpl_plate_limit_up_codes_info + + # if time_str >= '09:30:00': + # if stock_variables.浠婃棩澶у崟鏁版嵁 and stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋� and max( + # [len(stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋�.get(x, [])) for x in stock_variables.浠g爜鏉垮潡]) >= 3: + # compute_result = self.__run_backtest(code, stock_variables) + # self.__process_test_result(code, stock_variables, next_trade_day, stock_variables.褰撳墠浠�, + # time_str, compute_result) + + # if len(real_codes) >= 2 and time_str > '09:30:00': + # # print(time_str, plate) + # # 鎵捐繖涓澘鍧楅娑ㄦ鏁版渶澶氱殑绁� + # codes_infos = target_plate_codes_infos.get(plate) + # if codes_infos: + # for code_info in codes_infos: + # code = code_info[0] + # self.init_stock_variables(code, self.timeline_data, self.current_data) + # stock_variables: StockVariables = self.stock_variables_dict.get(code) + # compute_result = self.__run_backtest(code, stock_variables) + # if compute_result[0] and plate not in all_new_plates: + # all_new_plates.add(plate) + # print(plate, time_str, code_info, real_codes) + # else: + # pass + + # 澶у崟椹卞姩 + if current_big_orders and time_str >= '09:30:00': + for big_order in current_big_orders: + code = big_order[0] + if code not in self.fcodes: + continue + if self.target_codes and code not in self.target_codes: + continue + self.init_stock_variables(code, self.timeline_data, self.current_data) + stock_variables: StockVariables = self.stock_variables_dict.get(code) + if plate_limit_up_codes_info is not None: + stock_variables.鏉垮潡娑ㄥ仠 = plate_limit_up_codes_info + + if kpl_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒鏉垮潡娑ㄥ仠 = kpl_plate_limit_up_codes_info + + if kpl_head_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒棰嗘定鏉垮潡娑ㄥ仠 = kpl_head_plate_limit_up_codes_info + + if most_real_kpl_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋� = most_real_kpl_plate_limit_up_codes_info + + if block_in_datas: + stock_variables.璧勯噾娴佸叆鏉垮潡 = block_in_datas + + stock_variables.褰撳墠浠� = big_order[1][4] + try: + compute_result = self.__run_backtest(code, stock_variables) + # print(compute_result) + self.__process_test_result(code, stock_variables, next_trade_day, big_order[1][4], + huaxin_util.convert_time(big_order[1][3]), compute_result) + except Exception as e: + print(time_str) + logging.exception(e) + + print("鍙拱棰樻潗锛�", all_new_plates) + finally: + self.finish = True + + def run_v2(self): + def __compute_can_buy_plates(_current_limit_up_list): + # 缁熻浠g爜寮�1鏁伴噺:(娑ㄥ仠鏃堕棿,娑ㄥ仠鍘熷洜, 鏄惁浜屾澘, 鏄惁涓�鏉�) + code_info_dict = {x[0]: (tool.to_time_str(x[2]), x[5], 1 if kpl_util.get_high_level_count(x[4]) == 2 else 0, + 1 if kpl_util.get_high_level_count(x[4]) == 1 else 0) for x in + _current_limit_up_list} + plate_codes_dict = {} + # 鎸夋澘鍧楀垎绫� + for code in code_info_dict.keys(): + plates = code_plates.get(code) + if not plates: + plates = {code_info_dict.get(code)[1]} + plates -= constant.KPL_INVALID_BLOCKS + if plates: for p in plates: + if p not in plate_codes_dict: + plate_codes_dict[p] = set() + plate_codes_dict[p].add(code) + valid_plates = set() + for p in plate_codes_dict: + codes = list(plate_codes_dict[p]) + codes.sort(key=lambda x: code_info_dict[x][0]) + # 寮�1 浜屾澘鏁伴噺 + open_continue_2_count = sum( + [v[2] for k, v in code_info_dict.items() if k in codes and v[0] < '09:30:00']) + # 寮�1 棣栨澘鏁伴噺 + open_continue_1_count = sum( + [v[3] for k, v in code_info_dict.items() if k in codes and v[0] < '09:30:00']) + if open_continue_2_count >= 1 or open_continue_1_count >= 2: + valid_plates.add(p) + continue + if len(codes) >= 2 and tool.trade_time_sub(code_info_dict[codes[1]][0], + code_info_dict[codes[0]][0]) < 10 * 60: + # 鏈夆墺2涓定鍋滐紝涓斾袱涓定鍋滀箣闂撮棿闅斺墹10鍒嗛挓 + valid_plates.add(p) + continue + return valid_plates + + # 蹇�熸媺鍗囬┍鍔� + try: + self.load_data() + # print(self.fcodes) + limit_up_record_data_dict = {} + for limit_up_item in self.timeline_data["limit_up_record_data"]: + if limit_up_item[0] not in limit_up_record_data_dict: + limit_up_record_data_dict[limit_up_item[0]] = [] + limit_up_record_data_dict[limit_up_item[0]].append(limit_up_item) + self.timeline_data["limit_up_record_data"] = limit_up_record_data_dict + next_trade_day = self.timeline_data["next_trade_day"] + start_time, end_time = "09:25:00", "12:00:00" + # 鍒嗛挓K绾� + minute_bars_dict = {} + code_plates = self.current_data["code_plates"] + code_plates_for_refer = self.current_data["code_plates_for_refer"] + + # 鏉垮潡娑ㄥ仠浠g爜淇℃伅 + kpl_plate_limit_up_codes_info = None + plate_limit_up_codes_info = None + kpl_head_plate_limit_up_codes_info = None + + latest_current_limit_up_list = None + + latest_block_in_datas = None + + latest_can_buy_plates = set() + + # 鏍规嵁鏉垮潡鑾峰彇鐩爣绁� + target_plate_codes_infos = {} + for code in self.head_rise_code_blocks: + for p in self.head_rise_code_blocks[code]: + if p not in target_plate_codes_infos: + target_plate_codes_infos[p] = [] + target_plate_codes_infos[p].append(self.head_rise_code_blocks[code][p]) + for p in target_plate_codes_infos: + target_plate_codes_infos[p].sort(key=lambda x: x[1], reverse=True) + + all_new_plates = set() + + for i in range(60 * 60 * 5): + if self.finish: + break + time_str = tool.trade_time_add_second(start_time, i) + # print(f"[{tool.get_now_time_str()}]", time_str) + if time_str > end_time: + break + self.current_time = time_str + ticks = self.current_tick_data.get(time_str) if self.current_tick_data else None + # ===============缁熻褰撳墠娑ㄥ仠鏁版嵁 + origin_current_limit_up_list = self.current_data["limit_up_list"].get(time_str, []) + current_limit_up_list = [x for x in origin_current_limit_up_list if + kpl_util.get_high_level_count(x[4]) < 3] + + if current_limit_up_list: + latest_current_limit_up_list = current_limit_up_list + + if current_limit_up_list: + latest_can_buy_plates = __compute_can_buy_plates(current_limit_up_list) + plate_codes_info = {} + # 缁熻鏉垮潡娑ㄥ仠 + for x in current_limit_up_list: + # 鎸変唬鐮佺殑鏉垮潡缁熻娑ㄥ仠鏉垮潡涓殑浠g爜鏁伴噺 + # 娑ㄥ仠杩�1鍒嗛挓鎵嶇畻鏈夋晥娑ㄥ仠 + if tool.trade_time_sub(time_str, tool.timestamp_format(x[2], "%H:%M:%S")) < 60: + continue + plates = code_plates.get(x[0]) + if plates: + for p in plates: + if p not in plate_codes_info: + plate_codes_info[p] = [] + plate_codes_info[p].append((x[0], x[2])) + plate_limit_up_codes_info = plate_codes_info + + plate_codes_info = {} + for x in current_limit_up_list: + # 鎸夊紑鐩樺暒娑ㄥ仠鍘熷洜缁熻 + p = x[5] if p in constant.KPL_INVALID_BLOCKS: continue - new_plates.add(p) - for p in new_plates: if p not in plate_codes_info: plate_codes_info[p] = [] - plate_codes_info[p].append((x[0], x[2])) - kpl_head_plate_limit_up_codes_info = plate_codes_info + plate_codes_info[p].append((x[0], x[2], x[4])) + kpl_plate_limit_up_codes_info = plate_codes_info - # ==================娉ㄥ叆鏉垮潡娴佸叆 - block_in_datas = self.current_data["block_in"].get(time_str) - if block_in_datas: - blocks = [x[0] for x in block_in_datas if x[1] > 0] - block_in_datas = blocks[:20] - latest_block_in_datas = block_in_datas + # {"浠g爜":[(鏉垮潡浠g爜, 鏉垮潡鍚嶇О)]} + limit_up_plate_names_of_refer_code = self.current_data["limit_up_plate_names_of_refer_code"] + plate_codes_info = {} + for x in current_limit_up_list: + # 鎸夊紑鐩樺暒娑ㄥ仠鍘熷洜缁熻 + code = x[0] + # if code not in limit_up_plate_names_of_refer_code: + # continue + # 濡傛灉璁板綍娑ㄥ仠鏃堕棿杩囧幓20鍒嗛挓灏遍噰鐢ㄦ定鍋滈槦鍒楃殑娑ㄥ仠鍘熷洜 + if tool.trade_time_sub(time_str, tool.timestamp_format(x[2], "%H:%M:%S")) < 60 * 20 or True: + plates_infos = limit_up_plate_names_of_refer_code.get(code) + plates = set([d[1] for d in plates_infos if d[1] == x[5]]) if plates_infos else set() + else: + plates = {x[5]} - # ================褰撳墠鏃跺埢澶у崟 - current_big_orders = self.current_data["big_order"].get(time_str) - if current_big_orders: - for big_order in current_big_orders: - # 鏍煎紡 ("浠g爜", (涔板崟鍙�, 閲�, 閲戦, 鏃堕棿, 鏈�缁堟垚浜や环)) - self.init_stock_variables(big_order[0], self.timeline_data, self.current_data) - stock_variables: StockVariables = self.stock_variables_dict.get(big_order[0]) - if stock_variables.浠婃棩澶у崟鏁版嵁 is None: - stock_variables.浠婃棩澶у崟鏁版嵁 = [] - stock_variables.浠婃棩澶у崟鏁版嵁.append(big_order[1]) - # 缁熻澶у崟鍧囦环 - order_ids = set() - total_money = 0 - total_volume = 0 - for order in reversed(stock_variables.浠婃棩澶у崟鏁版嵁): - if order[0] in order_ids: - continue - order_ids.add(order[0]) - total_money += order[2] - total_volume += order[1] - if total_volume > 0: - stock_variables.浠婃棩澶у崟鍧囦环 = round(total_money / total_volume, 2) - else: - stock_variables.浠婃棩澶у崟鍧囦环 = 0 - current_big_sell_orders = self.current_data["big_sell_order"].get(time_str) - if current_big_sell_orders: - for big_order in current_big_sell_orders: - # 鏍煎紡 ("浠g爜", (涔板崟鍙�, 閲�, 閲戦, 鏃堕棿, 鏈�缁堟垚浜や环)) - self.init_stock_variables(big_order[0], self.timeline_data, self.current_data) - stock_variables: StockVariables = self.stock_variables_dict.get(big_order[0]) - if stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹� is None: - stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹� = [] - stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹�.append(big_order[1]) - - # 寮�鐩樺暒鏈�姝f定鍋滃師鍥� - most_real_kpl_plate_limit_up_codes_info = {} - # 鑾峰彇杩欎釜鏉垮潡鐨勭洰鏍囩エ - if kpl_plate_limit_up_codes_info: - current_limit_up_dict = {x[0]: x for x in latest_current_limit_up_list} - codes = set() - for plate in kpl_plate_limit_up_codes_info: - kpl_plate_codes = kpl_plate_limit_up_codes_info.get(plate) - codes |= set([x[0] for x in kpl_plate_codes]) - for code in codes: - plates = code_plates.get(code) - if not plates: - plates = {current_limit_up_dict.get(code)[5]} - plates -= constant.KPL_INVALID_BLOCKS - if plates: + new_plates = set() for p in plates: - if p not in most_real_kpl_plate_limit_up_codes_info: - most_real_kpl_plate_limit_up_codes_info[p] = [] - most_real_kpl_plate_limit_up_codes_info[p].append(code) + if p in constant.KPL_INVALID_BLOCKS: + continue + new_plates.add(p) + for p in new_plates: + if p not in plate_codes_info: + plate_codes_info[p] = [] + plate_codes_info[p].append((x[0], x[2])) + kpl_head_plate_limit_up_codes_info = plate_codes_info - if ticks: - for tick in ticks: - code = tick["symbol"][-6:] - # if code not in self.fcodes: - # continue - if DEBUG_CODES and code not in DEBUG_CODES: - continue + # ==================娉ㄥ叆鏉垮潡娴佸叆 + block_in_datas = self.current_data["block_in"].get(time_str) + if block_in_datas: + blocks = [x[0] for x in block_in_datas if x[1] > 0] + block_in_datas = blocks[:20] + latest_block_in_datas = block_in_datas - if code not in self.stock_variables_dict: - # 鍔犺浇鍩虹鏁版嵁 - self.init_stock_variables(code, self.timeline_data, self.current_data) - stock_variables: StockVariables = self.stock_variables_dict.get(code) - if plate_limit_up_codes_info is not None: - stock_variables.鏉垮潡娑ㄥ仠 = plate_limit_up_codes_info + # ================褰撳墠鏃跺埢澶у崟 + current_big_orders = self.current_data["big_order"].get(time_str) + if current_big_orders: + for big_order in current_big_orders: + # 鏍煎紡 ("浠g爜", (涔板崟鍙�, 閲�, 閲戦, 鏃堕棿, 鏈�缁堟垚浜や环)) + self.init_stock_variables(big_order[0], self.timeline_data, self.current_data) + stock_variables: StockVariables = self.stock_variables_dict.get(big_order[0]) + if stock_variables.浠婃棩澶у崟鏁版嵁 is None: + stock_variables.浠婃棩澶у崟鏁版嵁 = [] + stock_variables.浠婃棩澶у崟鏁版嵁.append(big_order[1]) + # 缁熻澶у崟鍧囦环 + order_ids = set() + total_money = 0 + total_volume = 0 + for order in reversed(stock_variables.浠婃棩澶у崟鏁版嵁): + if order[0] in order_ids: + continue + order_ids.add(order[0]) + total_money += order[2] + total_volume += order[1] + if total_volume > 0: + stock_variables.浠婃棩澶у崟鍧囦环 = round(total_money / total_volume, 2) + else: + stock_variables.浠婃棩澶у崟鍧囦环 = 0 + current_big_sell_orders = self.current_data["big_sell_order"].get(time_str) + if current_big_sell_orders: + for big_order in current_big_sell_orders: + # 鏍煎紡 ("浠g爜", (涔板崟鍙�, 閲�, 閲戦, 鏃堕棿, 鏈�缁堟垚浜や环)) + self.init_stock_variables(big_order[0], self.timeline_data, self.current_data) + stock_variables: StockVariables = self.stock_variables_dict.get(big_order[0]) + if stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹� is None: + stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹� = [] + stock_variables.浠婃棩鍗栧ぇ鍗曟暟鎹�.append(big_order[1]) - if kpl_plate_limit_up_codes_info is not None: - stock_variables.寮�鐩樺暒鏉垮潡娑ㄥ仠 = kpl_plate_limit_up_codes_info + # 寮�鐩樺暒鏈�姝f定鍋滃師鍥� + most_real_kpl_plate_limit_up_codes_info = {} + # 鑾峰彇杩欎釜鏉垮潡鐨勭洰鏍囩エ + if kpl_plate_limit_up_codes_info: + current_limit_up_dict = {x[0]: x for x in latest_current_limit_up_list} + codes = set() + for plate in kpl_plate_limit_up_codes_info: + kpl_plate_codes = kpl_plate_limit_up_codes_info.get(plate) + codes |= set([x[0] for x in kpl_plate_codes]) + for code in codes: + plates = code_plates.get(code) + if not plates: + plates = {current_limit_up_dict.get(code)[5]} + plates -= constant.KPL_INVALID_BLOCKS + if plates: + for p in plates: + if p not in most_real_kpl_plate_limit_up_codes_info: + most_real_kpl_plate_limit_up_codes_info[p] = [] + most_real_kpl_plate_limit_up_codes_info[p].append(code) + if ticks: + for tick in ticks: + code = tick["symbol"][-6:] + if code not in self.fcodes: + continue + if self.target_codes and code not in self.target_codes: + continue - if kpl_head_plate_limit_up_codes_info is not None: - stock_variables.寮�鐩樺暒棰嗘定鏉垮潡娑ㄥ仠 = kpl_head_plate_limit_up_codes_info + if code not in self.stock_variables_dict: + # 鍔犺浇鍩虹鏁版嵁 + self.init_stock_variables(code, self.timeline_data, self.current_data) + stock_variables: StockVariables = self.stock_variables_dict.get(code) + if plate_limit_up_codes_info is not None: + stock_variables.鏉垮潡娑ㄥ仠 = plate_limit_up_codes_info - stock_variables.鏉垮潡鎴愪氦浠g爜 = self.deal_block_codes - # 鏉垮潡娴佸叆鏁版嵁 - if latest_block_in_datas: - stock_variables.璧勯噾娴佸叆鏉垮潡 = latest_block_in_datas - # 鏆傛椂涓嶇敤鍒嗛挓K绾� - # if code not in minute_bars_dict: - # minute_bars_dict[code] = [tick] - # if minute_bars_dict[code][-1]["created_at"][:-2] == tick["created_at"][:-2]: - # # 缁熻鍒嗛挓K绾� - # minute_bars_dict[code][-1] = tick - # else: - # # 淇濆瓨鍒嗛挓K绾挎渶楂樹环 - # if not stock_variables.浠婃棩鏈�楂樹环: - # stock_variables.浠婃棩鏈�楂樹环 = minute_bars_dict[code][-1]["price"] - # if minute_bars_dict[code][-1]["price"] > stock_variables.浠婃棩鏈�楂樹环: - # stock_variables.浠婃棩鏈�楂樹环 = minute_bars_dict[code][-1]["price"] + if kpl_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒鏉垮潡娑ㄥ仠 = kpl_plate_limit_up_codes_info - # 淇濆瓨寮�鐩樹环 - if tick["created_at"][-8:] < '09:30:00': - stock_variables.浠婃棩寮�鐩樹环 = tick["price"] - # 浠婃棩寮�鐩樻定骞� - stock_variables.浠婃棩寮�鐩樻定骞� = round((tick["price"] - stock_variables.鏄ㄦ棩鏀剁洏浠�) / stock_variables.鏄ㄦ棩鏀剁洏浠�, - 4) - stock_variables.浠婃棩鎴愪氦閲� = tick["cum_volume"] - stock_variables.浠婃棩鎴愪氦棰� = tick["cum_amount"] - stock_variables.褰撳墠浠� = tick["price"] - if not stock_variables.浠婃棩閲忓淇℃伅: - if stock_variables.浠婃棩鎴愪氦閲� > stock_variables.鏄ㄦ棩鎴愪氦閲� * 0.8: - stock_variables.浠婃棩閲忓淇℃伅 = (time_str, stock_variables.褰撳墠浠�, round( - (stock_variables.褰撳墠浠� - stock_variables.鏄ㄦ棩鏀剁洏浠�) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2), - self.__statistic_big_order_info(stock_variables)) - if VOLUME_LOG_ENABLE: - # 缁熻澶у崟鍑�棰濓紝(50w浠ヤ笂,鍑�棰�,涔板崟涓暟/涔板崟鎬婚噾棰�,鍗栧崟涓暟/鍗栧崟鎬婚噾棰�) - print("****閲忓", code, stock_variables.浠婃棩閲忓淇℃伅) + if kpl_head_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒棰嗘定鏉垮潡娑ㄥ仠 = kpl_head_plate_limit_up_codes_info - # 缁熻浠婃棩鏈�楂樹环 - # if stock_variables.浠婃棩鏈�楂樹环 and tick["price"] > stock_variables.浠婃棩鏈�楂樹环: - # print(code, "====绐佺牬鍒嗘椂鏈�楂樹环锛�", tick["created_at"], tick["price"]) + stock_variables.鏉垮潡鎴愪氦浠g爜 = self.deal_block_codes + # 鏉垮潡娴佸叆鏁版嵁 + if latest_block_in_datas: + stock_variables.璧勯噾娴佸叆鏉垮潡 = latest_block_in_datas + # 鏆傛椂涓嶇敤鍒嗛挓K绾� + # if code not in minute_bars_dict: + # minute_bars_dict[code] = [tick] + # if minute_bars_dict[code][-1]["created_at"][:-2] == tick["created_at"][:-2]: + # # 缁熻鍒嗛挓K绾� + # minute_bars_dict[code][-1] = tick + # else: + # # 淇濆瓨鍒嗛挓K绾挎渶楂樹环 + # if not stock_variables.浠婃棩鏈�楂樹环: + # stock_variables.浠婃棩鏈�楂樹环 = minute_bars_dict[code][-1]["price"] + # if minute_bars_dict[code][-1]["price"] > stock_variables.浠婃棩鏈�楂樹环: + # stock_variables.浠婃棩鏈�楂樹环 = minute_bars_dict[code][-1]["price"] - if not stock_variables.浠婃棩鏈�楂樹环淇℃伅 or tick["price"] > stock_variables.浠婃棩鏈�楂樹环淇℃伅[0]: - stock_variables.浠婃棩鏈�楂樹环淇℃伅 = (tick["price"], time_str) + # 淇濆瓨寮�鐩樹环 + if tick["created_at"][-8:] < '09:30:00': + stock_variables.浠婃棩寮�鐩樹环 = tick["price"] + # 浠婃棩寮�鐩樻定骞� + stock_variables.浠婃棩寮�鐩樻定骞� = round( + (tick["price"] - stock_variables.鏄ㄦ棩鏀剁洏浠�) / stock_variables.鏄ㄦ棩鏀剁洏浠�, + 4) + stock_variables.浠婃棩鎴愪氦閲� = tick["cum_volume"] + stock_variables.浠婃棩鎴愪氦棰� = tick["cum_amount"] + stock_variables.褰撳墠浠� = tick["price"] + if not stock_variables.浠婃棩閲忓淇℃伅: + if stock_variables.浠婃棩鎴愪氦閲� > stock_variables.鏄ㄦ棩鎴愪氦閲� * 0.8: + stock_variables.浠婃棩閲忓淇℃伅 = (time_str, stock_variables.褰撳墠浠�, round( + (stock_variables.褰撳墠浠� - stock_variables.鏄ㄦ棩鏀剁洏浠�) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2), + self.__statistic_big_order_info(stock_variables)) + if VOLUME_LOG_ENABLE: + # 缁熻澶у崟鍑�棰濓紝(50w浠ヤ笂,鍑�棰�,涔板崟涓暟/涔板崟鎬婚噾棰�,鍗栧崟涓暟/鍗栧崟鎬婚噾棰�) + print("****閲忓", code, stock_variables.浠婃棩閲忓淇℃伅) - if not stock_variables.浠婃棩鏈�浣庝环 or tick["price"] < stock_variables.浠婃棩鏈�浣庝环: - stock_variables.浠婃棩鏈�浣庝环 = tick["price"] + # 缁熻浠婃棩鏈�楂樹环 + # if stock_variables.浠婃棩鏈�楂樹环 and tick["price"] > stock_variables.浠婃棩鏈�楂樹环: + # print(code, "====绐佺牬鍒嗘椂鏈�楂樹环锛�", tick["created_at"], tick["price"]) - stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋� = most_real_kpl_plate_limit_up_codes_info + if not stock_variables.浠婃棩鏈�楂樹环淇℃伅 or tick["price"] > stock_variables.浠婃棩鏈�楂樹环淇℃伅[0]: + stock_variables.浠婃棩鏈�楂樹环淇℃伅 = (tick["price"], time_str) - # compute_result = self.__run_backtest(code, stock_variables) - # self.__process_test_result(code, stock_variables, next_trade_day, stock_variables.褰撳墠浠�, - # time_str, compute_result) + if not stock_variables.浠婃棩鏈�浣庝环 or tick["price"] < stock_variables.浠婃棩鏈�浣庝环: + stock_variables.浠婃棩鏈�浣庝环 = tick["price"] + if most_real_kpl_plate_limit_up_codes_info: + stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋� = most_real_kpl_plate_limit_up_codes_info - # if len(real_codes) >= 2 and time_str > '09:30:00': - # # print(time_str, plate) - # # 鎵捐繖涓澘鍧楅娑ㄦ鏁版渶澶氱殑绁� - # codes_infos = target_plate_codes_infos.get(plate) - # if codes_infos: - # for code_info in codes_infos: - # code = code_info[0] - # self.init_stock_variables(code, self.timeline_data, self.current_data) - # stock_variables: StockVariables = self.stock_variables_dict.get(code) - # compute_result = self.__run_backtest(code, stock_variables) - # if compute_result[0] and plate not in all_new_plates: - # all_new_plates.add(plate) - # print(plate, time_str, code_info, real_codes) - # else: - # pass + # 璁$畻娑ㄩ��, 涓婁竴涓猼ick + if stock_variables.涓婁釜tick and stock_variables.涓婁釜tick['price'] > 0: + try: + time_space = tool.trade_time_sub(time_str, + stock_variables.涓婁釜tick["created_at"][-8:]) // 3 + if time_space > 0: + rate = (tick['price'] - stock_variables.涓婁釜tick[ + 'price']) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠� / time_space + stock_variables.娑ㄩ�� = round(rate, 2) + except: + print("") - # 澶у崟椹卞姩 - if current_big_orders and time_str >= '09:30:00': - for big_order in current_big_orders: - code = big_order[0] - if code not in self.fcodes: - continue - self.init_stock_variables(code, self.timeline_data, self.current_data) - stock_variables: StockVariables = self.stock_variables_dict.get(code) - if plate_limit_up_codes_info is not None: - stock_variables.鏉垮潡娑ㄥ仠 = plate_limit_up_codes_info + if stock_variables.娑ㄩ�� >= 0.8: + if code in self.target_codes: + print(time_str, code, f"蹇�熸媺鍗囷細{stock_variables.娑ㄩ�焳",f"浠g爜鏉垮潡锛歿stock_variables.浠g爜鏉垮潡}", f"鍙拱鏉垮潡锛歿latest_can_buy_plates}") + # 鍑嗗鏁版嵁 + if plate_limit_up_codes_info is not None: + stock_variables.鏉垮潡娑ㄥ仠 = plate_limit_up_codes_info - if kpl_plate_limit_up_codes_info is not None: - stock_variables.寮�鐩樺暒鏉垮潡娑ㄥ仠 = kpl_plate_limit_up_codes_info + if kpl_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒鏉垮潡娑ㄥ仠 = kpl_plate_limit_up_codes_info - if kpl_head_plate_limit_up_codes_info is not None: - stock_variables.寮�鐩樺暒棰嗘定鏉垮潡娑ㄥ仠 = kpl_head_plate_limit_up_codes_info + if kpl_head_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒棰嗘定鏉垮潡娑ㄥ仠 = kpl_head_plate_limit_up_codes_info - if most_real_kpl_plate_limit_up_codes_info is not None: - stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋� = most_real_kpl_plate_limit_up_codes_info + if most_real_kpl_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋� = most_real_kpl_plate_limit_up_codes_info - if block_in_datas: - stock_variables.璧勯噾娴佸叆鏉垮潡 = block_in_datas - compute_result = self.__run_backtest(code, stock_variables) - # print(compute_result) - self.__process_test_result(code, stock_variables, next_trade_day, big_order[1][4], - huaxin_util.convert_time(big_order[1][3]), compute_result) + if block_in_datas: + stock_variables.璧勯噾娴佸叆鏉垮潡 = block_in_datas - print("鍙拱棰樻潗锛�", all_new_plates) + stock_variables.鍙互涔扮殑鏉垮潡 = latest_can_buy_plates + try: + compute_result = self.__run_backtest(code, stock_variables) + # print(compute_result) + self.__process_test_result(code, stock_variables, next_trade_day, stock_variables.褰撳墠浠�, + time_str, compute_result) + except Exception as e: + print(time_str) + logging.exception(e) + stock_variables.涓婁釜tick = tick + + print("鍙拱棰樻潗锛�", all_new_plates) + finally: + self.finish = True def __process_test_result(self, code, stock_variables: StockVariables, next_trade_day, buy_price, time_str, compute_result): # if code == '000628': # print(time_str, code, compute_result) + # (鏃堕棿,(浠g爜,浠g爜鍚嶇О), 娑ㄥ箙 , 涔板叆缁撴灉) + backtest_result = [time_str, (code, gpcode_manager.get_code_name(code)), + round((buy_price - stock_variables.鏄ㄦ棩鏀剁洏浠�) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2), + compute_result] - if not compute_result[0]: - if code in DEBUG_CODES: - print(time_str, code, compute_result[1]) - # if compute_result[1].find("澶у崟") >= 0 or compute_result[1].find("浠锋牸瓒呰繃鏄ㄦ棩鏈�浣庝环") >= 0: - pass + try: + if not compute_result[0]: + if code in self.target_codes: + print(time_str, code, compute_result[1]) + # if compute_result[1].find("澶у崟") >= 0 or compute_result[1].find("浠锋牸瓒呰繃鏄ㄦ棩鏈�浣庝环") >= 0: + pass - # print(code, time_str,stock_variables.浠g爜鏉垮潡, compute_result) + # print(code, time_str,stock_variables.浠g爜鏉垮潡, compute_result) - if compute_result[0] and code not in self.deal_codes: - # 鏈�澶氫拱5涓� - if len(self.deal_codes) >= 100: - return - # if huaxin_util.convert_time(big_order[1][3]) >= "10:30:00" and len(deal_codes) > 0: - # break - self.deal_codes.add(code) - next_k_bars = self.data_loader.load_kline_data_by_day_and_code(next_trade_day, code) - current_k_bars = self.data_loader.load_kline_data_by_day_and_code(self.data_loader.now_day, - code) - if next_k_bars and buy_price: - t_rate = round((next_k_bars[0]["open"] - buy_price) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2) - t_rate = f"{t_rate}%" - else: - # 鑾峰彇褰撳墠鐨則ick绾� - if self.data_loader.now_day >= next_trade_day: - ticks = self.data_loader.jueJinLocalApi.get_history_tick_n(code, 1, frequency='tick', - end_date=f"{next_trade_day} 09:30:03") - else: - ticks = None - if ticks: - t_rate = round((ticks[-1]["price"] - buy_price) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2) + if compute_result[0] and code not in self.deal_codes: + # 鏈�澶氫拱5涓� + if len(self.deal_codes) >= 100: + return + # if huaxin_util.convert_time(big_order[1][3]) >= "10:30:00" and len(deal_codes) > 0: + # break + self.deal_codes.add(code) + next_k_bars = self.data_loader.load_kline_data_by_day_and_code(next_trade_day, code) + current_k_bars = self.data_loader.load_kline_data_by_day_and_code(self.data_loader.now_day, + code) + if next_k_bars and buy_price: + t_rate = round((next_k_bars[0]["open"] - buy_price) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2) t_rate = f"{t_rate}%" else: - t_rate = "鏈煡" - if current_k_bars and buy_price: - c_rate = round((current_k_bars[0]["close"] - buy_price) * 100 / current_k_bars[0]["pre_close"], 2) - c_rate = f"{c_rate}%" - else: - # 鎷夊彇褰撴棩K绾� - if tool.get_now_date_str() == self.data_loader.now_day and buy_price: - tick = self.data_loader.jueJinLocalApi.get_history_tick_n(code, 1, frequency='tick', - end_date=f"{self.data_loader.now_day} {tool.get_now_time_str()}") - c_rate = round((tick[0]["price"] - buy_price) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2) - else: - bar = self.data_loader.jueJinLocalApi.get_history_tick_n(code, 1, - end_date=f"{self.data_loader.now_day} 15:00:00") - if bar: - c_rate = round((bar[0]["close"] - buy_price) * 100 / bar[0]["pre_close"], 2) + # 鑾峰彇褰撳墠鐨則ick绾� + if self.data_loader.now_day >= next_trade_day: + ticks = self.data_loader.jueJinLocalApi.get_history_tick_n(code, 1, frequency='tick', + end_date=f"{next_trade_day} 09:30:03") else: - c_rate = "鏈煡" - print(f"{len(self.deal_codes)}==鍥炴祴缁撴灉锛�", code, gpcode_manager.CodesNameManager().get_code_name(code), - f"婧环鐜囷細{t_rate},褰撴棩鐩堜簭锛歿c_rate}锛屼笅鍗曟椂闂达細{time_str}锛屾定骞咃細{round((buy_price - stock_variables.鏄ㄦ棩鏀剁洏浠�) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2)}", - compute_result[1], - compute_result[2]) - for b in compute_result[3]: - if b not in self.deal_block_codes: - self.deal_block_codes[b] = set() - self.deal_block_codes[b].add(code) - stock_variables.鏉垮潡鎴愪氦浠g爜 = self.deal_block_codes + ticks = None + if ticks: + t_rate = round((ticks[-1]["price"] - buy_price) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2) + t_rate = f"{t_rate}%" + else: + t_rate = "鏈煡" + if current_k_bars and buy_price: + c_rate = round((current_k_bars[0]["close"] - buy_price) * 100 / current_k_bars[0]["pre_close"], 2) + c_rate = f"{c_rate}%" + else: + # 鎷夊彇褰撴棩K绾� + if tool.get_now_date_str() == self.data_loader.now_day and buy_price: + tick = self.data_loader.jueJinLocalApi.get_history_tick_n(code, 1, frequency='tick', + end_date=f"{self.data_loader.now_day} {tool.get_now_time_str()}") + c_rate = round((tick[0]["price"] - buy_price) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2) + else: + bar = self.data_loader.jueJinLocalApi.get_history_tick_n(code, 1, + end_date=f"{self.data_loader.now_day} 15:00:00") + if bar: + c_rate = round((bar[0]["close"] - buy_price) * 100 / bar[0]["pre_close"], 2) + else: + c_rate = "鏈煡" + backtest_result.append(c_rate) + backtest_result.append(t_rate) + print(f"{len(self.deal_codes)}==鍥炴祴缁撴灉锛�", code, gpcode_manager.CodesNameManager().get_code_name(code), + f"婧环鐜囷細{t_rate},褰撴棩鐩堜簭锛歿c_rate}锛屼笅鍗曟椂闂达細{time_str}锛屾定骞咃細{round((buy_price - stock_variables.鏄ㄦ棩鏀剁洏浠�) * 100 / stock_variables.鏄ㄦ棩鏀剁洏浠�, 2)}", + compute_result[1], + compute_result[2]) + for b in compute_result[3]: + if b not in self.deal_block_codes: + self.deal_block_codes[b] = set() + self.deal_block_codes[b].add(code) + stock_variables.鏉垮潡鎴愪氦浠g爜 = self.deal_block_codes + + finally: + self.backtest_results.append(backtest_result) -# DEBUG_CODES = ['002365', '000953', '002907', '002688', '003020', '002900', '002082', '000566', '300204', '002317'] -DEBUG_CODES = [] +# 閿傜數姹� ['002882', '002667', '002846', '300530', '002074', '301662', '002580', '300584', '603399', '601515'] +# 鍖栧伐 ['600610', '002427', '002165', '002809', '000565', '002365', '603192', '600370', '600800', '603188'] VOLUME_LOG_ENABLE = False # 澶囩敤澶у崟 @@ -779,16 +1118,24 @@ if __name__ == "__main__": back_test_dict = {} - # days = ["2025-05-06", "2025-05-07", "2025-05-08", "2025-05-09", "2025-05-12", "2025-05-13", "2025-05-14", - # "2025-05-15", "2025-05-16", "2025-05-19", "2025-05-20", "2025-05-21", "2025-05-22"] days = ["2025-05-12", "2025-05-13", "2025-05-14", "2025-05-15", "2025-05-16", "2025-05-19", "2025-05-20", "2025-05-21", "2025-05-22", "2025-05-23", "2025-05-26", "2025-05-27", "2025-05-28", "2025-05-29", "2025-05-30", "2025-06-03", "2025-06-04", "2025-06-05", "2025-06-06", "2025-06-09", "2025-06-10"] + days = ["2025-06-03", "2025-06-04", "2025-06-05", "2025-06-06", "2025-06-09", "2025-06-10", + "2025-06-11", "2025-06-12", "2025-06-13", "2025-06-16", "2025-06-17", "2025-06-18", "2025-06-19", + "2025-06-20", "2025-06-23", "2025-06-24", "2025-06-25", "2025-06-26", "2025-06-27", "2025-06-30", + "2025-07-01", "2025-07-02", "2025-07-03", "2025-07-04"] + + days = ["2025-07-04"] + # + # days = ["2025-05-12", "2025-05-13", "2025-05-14", "2025-05-15", "2025-05-16", "2025-05-19", "2025-05-20", + # "2025-05-21", "2025-05-22", "2025-05-23", "2025-05-26"] + days.reverse() for day in days: if day not in back_test_dict: # back_test_dict[day] = BackTest(day, "浠婃棩閲忔槸鍚﹁冻澶�.py") - back_test_dict[day] = BackTest(day, "浣庡惛鑴氭湰_杈ㄨ瘑搴v6.py") + back_test_dict[day] = BackTest(day, "strategy_script_v7.py", target_codes={}) print("=========================", day) # back_test_dict[day].run_volume() - back_test_dict[day].run() + back_test_dict[day].run_v2() -- Gitblit v1.8.0