From 245979e3907d34bcd88ac0c4547f399bf33a44de Mon Sep 17 00:00:00 2001 From: Administrator <admin@example.com> Date: 星期三, 18 六月 2025 18:13:30 +0800 Subject: [PATCH] bug修复/策略完善 --- strategy/test.py | 39 +++++-- strategy/data_analyzer.py | 46 +++++++- strategy/time_series_backtest.py | 8 - strategy/strategy_manager.py | 17 ++- trade/trade_manager.py | 150 ++++++++++++++++++++++++++---- strategy/strategy_variable_factory.py | 6 + utils/tool.py | 8 + strategy/strategy_script_v6.py | 3 strategy/strategy_variable.py | 1 9 files changed, 231 insertions(+), 47 deletions(-) diff --git a/strategy/data_analyzer.py b/strategy/data_analyzer.py index 7971c9d..cfdc57d 100644 --- a/strategy/data_analyzer.py +++ b/strategy/data_analyzer.py @@ -422,25 +422,57 @@ return count @classmethod - def is_too_high_and_not_relase_volume(cls, code, k_data): + def is_too_high_and_not_relase_volume(cls, k_data): """ - 闀垮緱澶珮涓旀病鏀鹃噺锛�30涓氦鏄撴棩鍐咃紝鍑虹幇杩囨渶浣庝环锛堟渶楂樹环涔嬪墠鐨勪氦鏄撴棩锛夊埌鏈�楂樹环涔嬮棿鐨勬定骞呪墺35%鐨勭エ锛屼笖浠婃棩璺濈鏈�楂樹环閭f棩鏃犳定鍋�/鏃犵偢鏉� + 闀垮緱澶珮涓旀病鏀鹃噺锛�30涓氦鏄撴棩鍐咃紝鍑虹幇杩囨渶浣庝环锛堟渶楂樹环涔嬪墠鐨勪氦鏄撴棩锛夊埌鏈�楂樹环涔嬮棿鐨勬定骞呪墺35%鐨勭エ锛屼笖浠婃棩璺濈鏈�楂樹环閭f棩鏃犳定鍋�/鏃犵偢鏉夸笖>=3鏉夸笖蹇呴』鏈�2杩炴澘 @param k_data: K绾挎暟鎹垪琛�(杩�150涓氦鏄撴棩锛屼笉鍖呭惈褰撳墠浜ゆ槗鏃ワ紝鏃堕棿鍊掑簭) @return: 鍥涜穼鍋滃強浠ヤ笂澶╂暟 """ k_data = k_data[:30] + code = k_data[0]["sec_id"] # 鑾峰彇鏈�楂樹环淇℃伅 max_high_price_data = max(k_data, key=lambda x: x["high"]) - min_close_price_data = min([d for d in k_data if d['bob'] < max_high_price_data['bob']], key=lambda x: x["close"]) - if (max_high_price_data['high'] - min_close_price_data['close'])/min_close_price_data['close'] < 0.35: + before_datas = [d for d in k_data if d['bob'] < max_high_price_data['bob']] + after_datas = [d for d in k_data if d['bob'] >= max_high_price_data['bob']] + if not before_datas: + return False + if len(before_datas) > 15: + # 浠庢渶楂樹环鏃ユ湡鍚戝墠鏈�澶氱湅15涓氦鏄撴棩 + before_datas = before_datas[:15] + min_close_price_data = min(before_datas, key=lambda x: x["close"]) + if (max_high_price_data['high'] - min_close_price_data['close']) / min_close_price_data['close'] < 0.35: # 娑ㄥ箙灏忎簬35% return False + before_k_datas = [d for d in k_data if min_close_price_data['bob'] <= d['bob'] <= max_high_price_data['bob']] + before_k_datas.sort(key=lambda x: x['bob']) + + # [鏈�浣庝环-鏈�楂樹环]鏃ユ湡鍐呮湁3涓澘涓旀湁涓よ繛鎵� + + continue_2_limit_up_date = None + for i in range(len(before_k_datas) - 1): + if cls.__is_limit_up(code, before_k_datas[i]["close"], + before_k_datas[i]["pre_close"]) and cls.__is_limit_up(code, + before_k_datas[i + 1]["close"], + before_k_datas[i + 1][ + "pre_close"]): + continue_2_limit_up_date = before_k_datas[i + 1]['bob'][:10] + break + if not continue_2_limit_up_date: + # 鏃犱袱杩炴澘 + return False + # 涓よ繛鏉夸箣鍚庢槸鍚︽湁鐐告澘/娑ㄥ仠 + # 鍙�2杩炴澘涔嬪悗鐨�3涓氦鏄撴棩 + temp_k_datas = [d for d in before_k_datas if d['bob'][:10] > continue_2_limit_up_date][:3] + if len([d for d in temp_k_datas if cls.__is_limit_up(code, d["high"], d["pre_close"])]) < 1: + # 涓よ繛鏉夸箣鍚庢湁涓定鍋�/鐐告澘涓旀椂闂村湪2杩炴澘涔嬪悗鐨�3涓氦鏄撴棩鍐� + return False + k_data = [d for d in k_data if d['bob'] > max_high_price_data['bob']] # 鍒ゆ柇鏄惁娑ㄥ仠杩� - if len([d for d in k_data if cls.__is_limit_up(code, d["high"], d["pre_close"])]) >0: - # 鏈�楂樹环涔嬪悗鏈夎繃娑ㄥ仠 + if len([d for d in k_data if cls.__is_limit_up(code, d["high"], d["pre_close"])]) > 0 or len(after_datas) >= 10: + # 鏈�楂樹环涔嬪悗鏈夎繃娑ㄥ仠鎴栬�呮槸鏈�楂樹环鍚�10涓氦鏄撴棩 return False - return True + return True, f"楂樹环鏃ユ湡锛歿max_high_price_data['bob'][:10]}锛屼綆浠锋棩鏈燂細{min_close_price_data['bob'][:10]}锛屼袱杩炴壋鏃ユ湡锛歿continue_2_limit_up_date}" class K60SLineAnalyzer: diff --git a/strategy/strategy_manager.py b/strategy/strategy_manager.py index d6acfb3..a9c585c 100644 --- a/strategy/strategy_manager.py +++ b/strategy/strategy_manager.py @@ -16,7 +16,7 @@ from strategy.strategy_variable_factory import DataLoader, StrategyVariableFactory import constant from third_data import kpl_util -from trade.trade_manager import DealCodesManager +from trade.trade_manager import DealCodesManager, PlatePlaceOrderManager from utils import huaxin_util, tool @@ -391,10 +391,14 @@ # 娉ㄥ叆鏉垮潡娴佸叆淇℃伅 if self.current_block_in_datas: sv.璧勯噾娴佸叆鏉垮潡 = self.current_block_in_datas - # 娉ㄥ叆宸叉垚浜や唬鐮� - place_order_plate_codes = DealCodesManager().get_place_order_plate_codes() + # 娉ㄥ叆宸叉垚浜や唬鐮�,鎴愪氦浠g爜浠ュ鎵樻暟鎹潵璁$畻 + place_order_plate_codes = PlatePlaceOrderManager().get_plate_codes() sv.鏉垮潡鎴愪氦浠g爜 = place_order_plate_codes - sv.鎴愪氦浠g爜 = DealCodesManager().get_deal_codes() + + code_sets = [set(lst) for lst in place_order_plate_codes.values()] + # 2. 浣跨敤 set.union() 姹傚苟闆� + union_code_sets = set().union(*code_sets) + sv.鎴愪氦浠g爜 = union_code_sets global_dict = { "sv": sv, "target_code": code, @@ -407,8 +411,11 @@ return # 鍙互涓嬪崟 # 鍒ゆ柇鏄惁鍙互涔� + order_ref = huaxin_util.create_order_ref() + price = tool.get_buy_max_price(sv.褰撳墠浠�) + volume = 100 + DealCodesManager().place_order(set(compute_result[3]), code, order_ref, price, volume) for b in compute_result[3]: - DealCodesManager().place_order(b, code) async_log_util.info(logger_trade, f"{code}涓嬪崟锛屾澘鍧楋細{compute_result[3]}") diff --git a/strategy/strategy_script_v6.py b/strategy/strategy_script_v6.py index 144d469..48bbf79 100644 --- a/strategy/strategy_script_v6.py +++ b/strategy/strategy_script_v6.py @@ -94,6 +94,9 @@ if sv.鏃ヤ笁鏉夸釜鏁癬10 >= 1: return False, f"10涓氦鏄撴棩鏈�>=3杩炴澘" + if sv.娑ㄥ緱楂樻湭鏀鹃噺: + return False, f"娑ㄥ緱楂樻湭鏀鹃噺" + # if sv.褰撳墠浠� > sv.鏄ㄦ棩鏈�浣庝环 * 1.1: # return False, f"涔板叆鏃剁殑浠锋牸蹇呴』鈮ゆ槰鏃ユ渶浣庝环*110%" diff --git a/strategy/strategy_variable.py b/strategy/strategy_variable.py index e2b805f..74ca857 100644 --- a/strategy/strategy_variable.py +++ b/strategy/strategy_variable.py @@ -213,6 +213,7 @@ self.杈ㄨ瘑搴︿唬鐮� = set() self.棰嗘定鏉垮潡淇℃伅 = set() self.杩炵画鑰侀鏉� = set() + self.娑ㄥ緱楂樻湭鏀鹃噺 = False def replace_variables(self, expression): """ diff --git a/strategy/strategy_variable_factory.py b/strategy/strategy_variable_factory.py index 7a29a7e..2b3d3d1 100644 --- a/strategy/strategy_variable_factory.py +++ b/strategy/strategy_variable_factory.py @@ -602,6 +602,12 @@ kline_data_60s = kline_data_60s_dict.get(trade_days[0]) fdata = K60SLineAnalyzer.get_close_price_of_max_volume(kline_data_60s) instance.__setattr__(f"鏄ㄦ棩鍒嗘椂鏈�楂橀噺浠�", fdata) + + if KTickLineAnalyzer.is_too_high_and_not_relase_volume(kline_data_1d): + instance.娑ㄥ緱楂樻湭鏀鹃噺 = True + else: + instance.娑ㄥ緱楂樻湭鏀鹃噺 = False + return instance diff --git a/strategy/test.py b/strategy/test.py index 872dfb9..a916c50 100644 --- a/strategy/test.py +++ b/strategy/test.py @@ -1,13 +1,15 @@ from huaxin_client import l1_subscript_codes_manager -from strategy import strategy_manager +from strategy import strategy_manager, data_analyzer from strategy.strategy_variable import StockVariables # 缁熻褰撴棩鐨勫钩鍧囨孩浠风巼 +from strategy.strategy_variable_factory import DataLoader from third_data.kpl_block_manager import KPLCodeJXBlocksManager def statistic_average(path): rate_list = [] + yjl_list = [] with open(path, mode='r', encoding='utf-8') as f: lines = f.readlines() for line in lines: @@ -17,22 +19,39 @@ continue r = round(float(line.split("褰撴棩鐩堜簭锛�")[1].split("锛�")[0].replace("%", "")), 2) rate_list.append(r) - print("骞冲潎鍒╂鼎鐜囷細", round(sum(rate_list) / len(rate_list), 2)) - print("鎬诲埄娑︾巼锛�", round(sum(rate_list), 2), "鎬讳拱绁ㄦ暟閲忥細", len(rate_list)) + r = line.split("婧环鐜囷細")[1].split(",")[0].replace("%", "") + if r.find("鏈煡") < 0: + yjl_list.append(round(float(r), 2)) + print("褰撴棩骞冲潎鍒╂鼎鐜囷細", round(sum(rate_list) / len(rate_list), 2)) + print("褰撴棩鎬诲埄娑︾巼锛�", round(sum(rate_list), 2), "鎬讳拱绁ㄦ暟閲忥細", len(rate_list)) + print("娆℃棩寮�鐩樺钩鍧囧埄娑︾巼锛�", round(sum(yjl_list) / len(yjl_list), 2)) + print("娆℃棩寮�鐩樻�诲埄娑︾巼锛�", round(sum(yjl_list), 2), "鎬讳拱绁ㄦ暟閲忥細", len(yjl_list)) if __name__ == "__main__": + print("======3涓エ娑ㄥ仠涔嬪悗涔癬涓嶄拱闀垮緱澶珮鏈斁閲�") + statistic_average(r"C:\Users\Administrator\Desktop\3涓エ娑ㄥ仠涔嬪悗涔癬涓嶄拱闀垮緱澶珮鏈斁閲�.txt") print("======3涓エ娑ㄥ仠涔嬪悗涔�") statistic_average(r"C:\Users\Administrator\Desktop\3涓エ娑ㄥ仠涔嬪悗涔�.txt") - # print("======3涓エ娑ㄥ仠涔嬪悗涔�+涓嶉檺寮�鐩樻定骞�+3涓定鍋滀箣鍚庡ぇ鍗曟墦鎶�") - # statistic_average(r"C:\Users\Administrator\Desktop\3涓エ娑ㄥ仠涔嬪悗涔癬涓嶉檺寮�鐩樻定骞�.txt") - codes = set() - codes_sh, codes_sz = l1_subscript_codes_manager.get_codes() - codes |= set([x.decode() for x in codes_sh]) - codes |= set([x.decode() for x in codes_sz]) - KPLCodeJXBlocksManager('2025-06-17', codes).start_download_blocks() + # codes = set() + # codes_sh, codes_sz = l1_subscript_codes_manager.get_codes() + # codes |= set([x.decode() for x in codes_sh]) + # codes |= set([x.decode() for x in codes_sz]) + # KPLCodeJXBlocksManager('2025-06-17', codes).start_download_blocks() # target_block = {"鐭虫补鐭冲寲", "澶╃劧姘�", "鍖栧伐"} # for code in code_blocks: # blocks = code_blocks.get(code) # if len(blocks & target_block) == len(target_block): # print(code, blocks) + + __DataLoader = DataLoader("2025-06-18") + kline_datas = __DataLoader.load_kline_data() + codes = [] + for code in kline_datas: + # if code !='003010': + # continue + result = data_analyzer.KTickLineAnalyzer.is_too_high_and_not_relase_volume(kline_datas[code]) + if result: + print("鏈斁閲�", code, result[1]) + codes.append(code) + print(len(codes)) diff --git a/strategy/time_series_backtest.py b/strategy/time_series_backtest.py index b8902e4..aa984fb 100644 --- a/strategy/time_series_backtest.py +++ b/strategy/time_series_backtest.py @@ -807,13 +807,11 @@ if __name__ == "__main__": back_test_dict = {} - 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"] # 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", - # "2025-06-11", "2025-06-12", "2025-06-13", "2025-06-16", "2025-06-17"] + # "2025-05-30", "2025-06-03"] + 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"] # days = ["2025-05-23"] diff --git a/trade/trade_manager.py b/trade/trade_manager.py index 56ab205..ad55349 100644 --- a/trade/trade_manager.py +++ b/trade/trade_manager.py @@ -176,14 +176,11 @@ def __init__(self): self.musql = Mysqldb() + # 鎴愪氦寰楄鍗曚俊鎭� self.__deal_code_orders_info = {} - self.redis_manager = redis_manager.RedisManager(12) - # 涓嬭繃鍗曠殑鏉垮潡浠g爜 - self.__place_order_plate_codes_info = {} + # 濮旀墭寰楄鍗曚俊鎭細{code#order_ref:} + self.__delegate_code_orders = {} self.__load_data() - - def __get_redis(self): - return self.redis_manager.getRedis() def __load_data(self): # 涓嶇畻鎵撴澘鐨勬暟鎹� @@ -193,13 +190,9 @@ for r in results: self.add_deal_order(r[1], r[4], round(float(r[3]), 2), r[0], r[2]) - val = RedisUtils.get(self.__get_redis(), "place_order_plate_codes_info") - if val: - self.__place_order_plate_codes_info = json.loads(val) - def add_deal_order(self, code, volume, price, trade_id, order_sys_id): """ - 娣诲姞鎴愪氦澶у崟 + 娣诲姞鎴愪氦璁㈠崟 @param code: @param volume: @param price: @@ -217,31 +210,148 @@ return self.__deal_code_orders_info[code][trade_id] = (volume, price, order_sys_id) + def set_order_status(self, code, order_ref, order_sys_id, price, volume, status): + """ + 璁剧疆璁㈠崟鐘舵�� + @param code: + @param order_ref: + @param order_sys_id: + @param price: + @param volume: + @param status: + @return: + """ + k = f"{code}#{order_ref}" + if k not in self.__delegate_code_orders: + return + # [浠g爜锛岃鍗曠储寮曪紝璁㈠崟鍙凤紝浠锋牸锛岄噺锛岀姸鎬侊紝鏉垮潡闆嗗悎] + data = self.__delegate_code_orders[k] + data[2] = order_sys_id + data[5] = status + data[3] = price + data[4] = volume + # 濡傛灉璁㈠崟宸茬粡鍙栨秷灏遍渶瑕佸垹闄� + if status == huaxin_util.TORA_TSTP_OST_AllCanceled or status == huaxin_util.TORA_TSTP_OST_Rejected: + data = self.__delegate_code_orders.pop(k) + if data: + PlatePlaceOrderManager().remove_plates_code(data[6], code) + def get_deal_codes(self): if not self.__deal_code_orders_info: return set() return set(self.__deal_code_orders_info.keys()) - def place_order(self, plate, code): + def place_order(self, plates, code, order_ref, price, volume): """ 涓嬪崟 - @param plate: + @param plates: + @param code: + @param order_ref: + @param price: + @param volume: + @return: + """ + # 鍒濆鍖栧鎵樻暟鎹� [浠g爜锛岃鍗曠储寮曪紝璁㈠崟鍙凤紝浠锋牸锛岄噺锛岀姸鎬侊紝鏉垮潡闆嗗悎] + data = [code, order_ref, '', price, volume, huaxin_util.TORA_TSTP_OST_Unknown, plates] + k = f"{code}#{order_ref}" + if k not in self.__delegate_code_orders: + self.__delegate_code_orders[k] = data + PlatePlaceOrderManager().add_plates_code(plates, code) + + def place_order_fail(self, code, order_ref): + """ + 涓嬪崟澶辫触浜� + @param code: + @param order_ref: + @return: + """ + k = f"{code}#{order_ref}" + if k in self.__delegate_code_orders: + data = self.__delegate_code_orders.pop(k) + if data: + PlatePlaceOrderManager().remove_plates_code(data[6], code) + + def get_deal_or_delegated_codes(self): + """ + 鑾峰彇宸茬粡鎴愪氦鎴栬�呭鎵樼殑浠g爜 + @return: + """ + codes = set() + if self.__delegate_code_orders: + for k in self.__delegate_code_orders: + codes.add(self.__delegate_code_orders[k][0]) + + if self.__deal_code_orders_info: + codes |= set(self.__deal_code_orders_info.keys()) + return codes + + +@tool.singleton +class PlatePlaceOrderManager: + """ + 鏉垮潡涓嬪崟绠$悊 + """ + + def __init__(self): + self.__db = 12 + self.redis_manager = redis_manager.RedisManager(self.__db) + # 涓嬭繃鍗曠殑鏉垮潡浠g爜 + self.__place_order_plate_codes_info = {} + self.__load_data() + + def __get_redis(self): + return self.redis_manager.getRedis() + + def __load_data(self): + val = RedisUtils.get(self.__get_redis(), "place_order_plate_codes_info") + if val: + self.__place_order_plate_codes_info = json.loads(val) + + def add_plates_code(self, plates, code): + """ + 娣诲姞鏉垮潡涓嬪崟 + @param plates: @param code: @return: """ - if plate not in self.__place_order_plate_codes_info: - self.__place_order_plate_codes_info[plate] = [] - if code not in self.__place_order_plate_codes_info[plate]: - self.__place_order_plate_codes_info[plate].append(code) + for plate in plates: + if plate not in self.__place_order_plate_codes_info: + self.__place_order_plate_codes_info[plate] = [] + if code not in self.__place_order_plate_codes_info[plate]: + self.__place_order_plate_codes_info[plate].append(code) + self.__sync_plate_place_order_info() + + def __sync_plate_place_order_info(self): + """ + 鍚屾鏉垮潡涓嬪崟淇℃伅 + @return: + """ RedisUtils.setex_async(self.__db, "place_order_plate_codes_info", tool.get_expire(), json.dumps(self.__place_order_plate_codes_info)) - def get_place_order_plate_codes(self): + def remove_plates_code(self, plates, code): + """ + 绉婚櫎鏉垮潡涓嬪崟 + @param plates: + @param code: + @return: + """ + for plate in plates: + if plate in self.__place_order_plate_codes_info: + if code in self.__place_order_plate_codes_info[plate]: + self.__place_order_plate_codes_info[plate].remove(code) + self.__sync_plate_place_order_info() + + def get_plate_codes(self): return self.__place_order_plate_codes_info __CodesTradeStateManager = CodesTradeStateManager() if __name__ == "__main__": - codes = DealCodesManager().get_codes() - print(codes) + PlatePlaceOrderManager().add_plates_code({"閫氫俊","璁$畻鏈�"}, "000333") + place_order_plate_codes = PlatePlaceOrderManager().get_plate_codes() + code_sets = [set(lst) for lst in place_order_plate_codes.values()] + # 2. 浣跨敤 set.union() 姹傚苟闆� + union_code_sets = set().union(*code_sets) + print(union_code_sets) diff --git a/utils/tool.py b/utils/tool.py index e191df7..9dff785 100644 --- a/utils/tool.py +++ b/utils/tool.py @@ -318,6 +318,14 @@ return max(price1, price2) +# 鑾峰彇涔板叆浠锋牸绗煎瓙鐨勬渶楂樹环 +def get_buy_max_price(price): + price1 = price * (1 + 0.02) + price1 = math.ceil(price1 * 100) / 100 + price2 = price + 0.1 + return max(price1, price2) + + # 鑾峰彇涔板叆浠锋牸绗煎瓙鐨勬渶浣庝环 def get_shadow_price(price): # fprice = round((100 - random.randint(2, 10)) * price / 100, 2) -- Gitblit v1.8.0