From bb2c567db00cc12b16808fc71bbb4c91615d110b Mon Sep 17 00:00:00 2001 From: Administrator <admin@example.com> Date: 星期一, 30 六月 2025 17:20:18 +0800 Subject: [PATCH] bug修复/策略完善 --- strategy/time_series_backtest.py | 750 ++++++++++++++++++++++++++++----------------------------- 1 files changed, 365 insertions(+), 385 deletions(-) diff --git a/strategy/time_series_backtest.py b/strategy/time_series_backtest.py index 37775a5..e4c0a5b 100644 --- a/strategy/time_series_backtest.py +++ b/strategy/time_series_backtest.py @@ -14,7 +14,8 @@ 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: @@ -27,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 @@ -41,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 @@ -250,43 +254,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 @@ -321,8 +288,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] @@ -332,8 +297,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): @@ -417,391 +381,407 @@ 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() - for p in plates: - if p in constant.KPL_INVALID_BLOCKS: + # 寮�鐩樺暒鏈�姝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 - 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 - - # ==================娉ㄥ叆鏉垮潡娴佸叆 - 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 - - # ================褰撳墠鏃跺埢澶у崟 - 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: + if self.target_codes and code not in self.target_codes: 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: - 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]) + 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 - # ---------娴嬭瘯-------- - # 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 kpl_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒鏉垮潡娑ㄥ仠 = kpl_plate_limit_up_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 + 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: - # 鍔犺浇鍩虹鏁版嵁 + 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 + 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_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 - 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 most_real_kpl_plate_limit_up_codes_info is not None: + stock_variables.寮�鐩樺暒鏈�姝f澘鍧楁定鍋� = most_real_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 block_in_datas: + stock_variables.璧勯噾娴佸叆鏉垮潡 = block_in_datas - # 缁熻浠婃棩鏈�楂樹环 - # if stock_variables.浠婃棩鏈�楂樹环 and tick["price"] > stock_variables.浠婃棩鏈�楂樹环: - # print(code, "====绐佺牬鍒嗘椂鏈�楂樹环锛�", tick["created_at"], tick["price"]) + 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) - 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 DEBUG_CODES and code not in DEBUG_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) + 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) # 閿傜數姹� ['002882', '002667', '002846', '300530', '002074', '301662', '002580', '300584', '603399', '601515'] # 鍖栧伐 ['600610', '002427', '002165', '002809', '000565', '002365', '603192', '600370', '600800', '603188'] -DEBUG_CODES = ['605005', '002590', '002813', '000826', '002973', '603686', '001230', '600684', '000981', '002232'] -# DEBUG_CODES = [] VOLUME_LOG_ENABLE = False # 澶囩敤澶у崟 @@ -818,7 +798,7 @@ "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-20", "2025-06-23", "2025-06-24", "2025-06-25", "2025-06-26", "2025-06-27", "2025-06-30"] # days = ["2025-05-23"] # -- Gitblit v1.8.0