添加新的策略

This commit is contained in:
jackyu66git
2026-05-19 09:58:33 +08:00
parent 5dc0c4cffd
commit 91148a648a
9 changed files with 1377 additions and 115 deletions
+318 -8
View File
@@ -157,15 +157,41 @@ class TF_DF():
klu_state_list.append("00")
print(klu_state_list[:20])
return klu_state_list
def get_bsp_state(self, dataframe):
def get_bsp_signal_data(self, dataframe):
klu_list = self.get_klu_list(dataframe)
klc_list = self.get_klc_list(klu_list)
bi_list = self.cal_bi_list(klc_list)
seg_list = self.get_seg_list(bi_list)
bi_zs_list = self.cal_bi_zs(seg_list)
bi_zs_list = self.cal_bi_zs_list_pure(bi_list)
bsp_list = self.find_all_bsp(bi_list, bi_zs_list)
bsp_by_bi_type = {}
for bsp in bsp_list:
if bsp and bsp.bi:
bsp_by_bi_type[(bsp.bi.index, bsp.type)] = bsp
bsp_state_list = [0] * len(dataframe)
bsp_zg_list = [0.0] * len(dataframe)
bsp_zd_list = [0.0] * len(dataframe)
bsp_stop_price_list = [0.0] * len(dataframe)
bsp_risk_ratio_list = [0.0] * len(dataframe)
klc_index = 0
def set_bsp_signal(index, state, bsp):
bsp_state_list[index] = state
if not bsp or not bsp.zs:
return
close = float(dataframe.iloc[index]['close'])
atr = float(dataframe.iloc[index]['atr']) if 'atr' in dataframe.columns and not pd.isna(dataframe.iloc[index]['atr']) else 0.0
atr_ratio = atr / close if close > 0 else 0.0
buffer = atr * 0.1
bsp_zg_list[index] = bsp.zs.zg
bsp_zd_list[index] = bsp.zs.zd
if state == -1:
stop_price = bsp.zs.zg - buffer
risk_ratio = (close - stop_price) / close if close > stop_price else atr_ratio
else:
stop_price = bsp.zs.zd + buffer
risk_ratio = (stop_price - close) / close if close < stop_price else atr_ratio
bsp_stop_price_list[index] = stop_price
bsp_risk_ratio_list[index] = max(0.001, min(float(risk_ratio), 0.02))
for index in range(0, len(dataframe)):
if klc_index == len(klc_list):
klc_index = len(klc_list) - 1
@@ -175,7 +201,7 @@ class TF_DF():
bi = klc.bi.pre
if bi and bi.is_sure and bi.end_klc.bsp_type == Chan_BSP_TYPE.B3:
# 第三类买点
bsp_state_list[index] = -1
set_bsp_signal(index, -1, bsp_by_bi_type.get((bi.index, Chan_BSP_TYPE.B3)))
#print(klc.end_time, "B3")
else:
bsp_state_list[index] = 0
@@ -183,14 +209,22 @@ class TF_DF():
bi = klc.bi.pre
if bi and bi.is_sure and bi.end_klc.bsp_type == Chan_BSP_TYPE.S3:
# 第三类卖点
bsp_state_list[index] = 1
set_bsp_signal(index, 1, bsp_by_bi_type.get((bi.index, Chan_BSP_TYPE.S3)))
#print(klc.end_time, "S3")
else:
bsp_state_list[index] = 0
klc_index += 1
else:
bsp_state_list[index] = 0
return bsp_state_list
return {
'bsp_state': bsp_state_list,
'bsp_zg': bsp_zg_list,
'bsp_zd': bsp_zd_list,
'bsp_stop_price': bsp_stop_price_list,
'bsp_risk_ratio': bsp_risk_ratio_list,
}
def get_bsp_state(self, dataframe):
return self.get_bsp_signal_data(dataframe)['bsp_state']
def get_ema_state(self, dataframe):
klu_list = self.get_klu_list(dataframe)
klc_list = self.get_klc_list(klu_list)
@@ -1316,7 +1350,7 @@ class TF_DF():
if (last_top.low < klc.pre.high or last_top.low < klc.next.high) and (klc.index - last_top.index < 100):
return False
return True
# 建议用这种方式生成笔中枢
# 线段内的中枢
def cal_bi_zs(self, seg_list):
bi_zs_list = []
for seg in seg_list:
@@ -1324,7 +1358,7 @@ class TF_DF():
if len(zs_list) > 0:
bi_zs_list = list(bi_zs_list) + list(zs_list)
return bi_zs_list
# 这个种方式不是很好,会有很多重叠的
# 跨段不相连的中枢
def cal_bi_zs_list(self, bi_list):
"""
根据缠论笔中枢定义计算中枢(参照 get_zs_list 线段中枢判断规则)
@@ -1455,6 +1489,282 @@ class TF_DF():
if last_bi_of_zs.is_sure:
last_zs.set_end_bi(last_bi_of_zs, last_bi_of_zs.sure_time)
return bi_zs_list
def get_bi_zs_list(self, bi_list):
"""
根据缠论笔中枢定义计算中枢(完全参照 get_seg_zs_list 线段中枢判断规则)
从第4根笔开始(索引3),每3根笔为一组检查
上涨中枢:后中枢 zd > 前中枢 zg(不重叠上移)
下跌中枢:后中枢 zg < 前中枢 zd(不重叠下移)
盘整/扩张:后中枢与前中枢整体区间有交集 → 合并扩展
中枢可按两笔一组继续扩展到5根、7根...
"""
bi_zs_list = []
if len(bi_list) < 3:
return bi_zs_list
last_zs = None
start_idx = 3
while start_idx < len(bi_list):
if start_idx + 2 >= len(bi_list):
break
bi1 = bi_list[start_idx]
bi2 = bi_list[start_idx + 1]
bi3 = bi_list[start_idx + 2]
if not (bi1.is_sure and bi2.is_sure and bi3.is_sure):
start_idx += 1
continue
zg = min(bi1.high, bi2.high, bi3.high)
zd = max(bi1.low, bi2.low, bi3.low)
if zg <= zd:
start_idx += 1
continue
valid = False
if last_zs is None:
if bi1.dir == Chan_BI_DIR.DOWN:
zs_dir = Chan_ZS_DIR.UP
valid = (bi2.dir == Chan_BI_DIR.UP and bi3.dir == Chan_BI_DIR.DOWN)
else:
zs_dir = Chan_ZS_DIR.DOWN
valid = (bi2.dir == Chan_BI_DIR.DOWN and bi3.dir == Chan_BI_DIR.UP)
else:
is_up_zs = zd > last_zs.zg
is_down_zs = zg < last_zs.zd
if is_up_zs:
zs_dir = Chan_ZS_DIR.UP
valid = (bi1.dir == Chan_BI_DIR.DOWN and bi2.dir == Chan_BI_DIR.UP and bi3.dir == Chan_BI_DIR.DOWN)
elif is_down_zs:
zs_dir = Chan_ZS_DIR.DOWN
valid = (bi1.dir == Chan_BI_DIR.UP and bi2.dir == Chan_BI_DIR.DOWN and bi3.dir == Chan_BI_DIR.UP)
create_new_zs = False
if not valid:
# 如果新中枢和前一个中枢的中枢区间有重叠,不形成新中枢,合并扩展
if last_zs is not None:
is_in_last_zs = (zd > last_zs.zd and zd < last_zs.zg) or \
(zg < last_zs.zg and zg > last_zs.zd) or \
(zg > last_zs.zg and zd < last_zs.zd) or \
(zg < last_zs.zg and zd > last_zs.zd)
if is_in_last_zs:
# 扩展当前中枢:将 bi1-bi3 加入 last_zs
for bi in [bi1, bi2, bi3]:
if bi not in last_zs.bi_list:
last_zs.add_bi(bi)
create_new_zs = False
else:
start_idx += 1
continue
else:
start_idx += 1
continue
else:
create_new_zs = True
# 新中枢形成时确认前一个中枢
if last_zs and create_new_zs:
last_bi = last_zs.bi_list[-1]
if last_bi and last_bi.is_sure:
last_zs.is_sure = True
last_zs.set_end_bi(last_bi, last_bi.sure_time)
zs = last_zs
if create_new_zs:
gg = max(bi1.high, bi2.high, bi3.high)
dd = min(bi1.low, bi2.low, bi3.low)
zs = ChanBIZS(bi1, len(bi_zs_list), zs_dir)
zs.set_zg(zg)
zs.set_zd(zd)
zs.set_gg(gg)
zs.set_dd(dd)
zs.is_sure = False
zs.bi_list = [bi1, bi2, bi3]
# 离开后回抽扩展检查
added_after_leave = []
leave_index = start_idx + 4
while leave_index < len(bi_list):
b = bi_list[leave_index]
if not b.is_sure:
break
if b.high >= zs.zd and b.low <= zs.zg:
added_after_leave.append(b.pre)
added_after_leave.append(b)
else:
break
leave_index += 2
if added_after_leave:
bis_for_zs = list(zs.bi_list) + list(added_after_leave)
bi_highs = [bi.high for bi in bis_for_zs]
bi_lows = [bi.low for bi in bis_for_zs]
zs.set_gg(max(bi_highs))
zs.set_dd(min(bi_lows))
zs.bi_list = bis_for_zs
bi = bis_for_zs[-1]
if bi.is_sure:
zs.set_end_bi(bi, bi.sure_time)
start_idx = start_idx + len(added_after_leave)
else:
if create_new_zs:
zs.set_end_bi(bi3, bi3.sure_time)
if create_new_zs:
if last_zs:
last_zs.set_next(zs)
zs.set_pre(last_zs)
bi_zs_list.append(zs)
last_zs = zs
start_idx += 4
# 最后一个中枢:根据 bi_list 最后一笔确认状态
if last_zs:
last_zs.is_sure = bi_list[-1].is_sure
if last_zs and not last_zs.is_sure:
if last_zs.bi_list and len(last_zs.bi_list) > 0:
last_bi_of_zs = last_zs.bi_list[-1]
last_bi_idx = -1
for i, bi in enumerate(bi_list):
if bi == last_bi_of_zs:
last_bi_idx = i
break
has_leave = False
if last_bi_idx >= 0 and last_bi_idx + 1 < len(bi_list):
for i in range(last_bi_idx + 1, len(bi_list)):
bi = bi_list[i]
if bi.is_sure:
leave = (bi.low > last_zs.zg and bi.high > last_zs.zg) or \
(bi.high < last_zs.zd and bi.low < last_zs.zd)
if leave:
has_leave = True
break
if has_leave:
if last_bi_of_zs.is_sure:
last_zs.set_end_bi(last_bi_of_zs, last_bi_of_zs.sure_time)
return bi_zs_list
def cal_bi_zs_list_pure(self, bi_list):
bi_zs_list = []
if len(bi_list) < 3:
return bi_zs_list
def get_zs_range(bis):
zg = min(bi.high for bi in bis)
zd = max(bi.low for bi in bis)
return zg, zd
def is_bi_overlap_range(bi, zg, zd):
return bi.high >= zd and bi.low <= zg
def check_zs_position_filter(last_zs, zg, zd, bis):
if last_zs is None:
return True
if zg <= last_zs.zd:
return bis[0].dir == Chan_BI_DIR.UP and bis[-1].dir == Chan_BI_DIR.UP
if zd >= last_zs.zg:
return bis[0].dir == Chan_BI_DIR.DOWN and bis[-1].dir == Chan_BI_DIR.DOWN
return True
def set_zs_bi_list(zs, bis):
zs.bi_list = list(bis)
for bi in zs.bi_list:
bi.set_bi_zs(zs)
zs.set_gg(max(bi.high for bi in zs.bi_list))
zs.set_dd(min(bi.low for bi in zs.bi_list))
zs.classify_zs()
last_zs = None
start_idx = 0
while start_idx + 2 < len(bi_list):
bi1 = bi_list[start_idx]
bi2 = bi_list[start_idx + 1]
bi3 = bi_list[start_idx + 2]
if not (bi1.is_sure and bi2.is_sure and bi3.is_sure):
start_idx += 1
continue
if not (bi1.dir != bi2.dir and bi1.dir == bi3.dir):
start_idx += 1
continue
zg, zd = get_zs_range([bi1, bi2, bi3])
if zg <= zd:
start_idx += 1
continue
bis_for_zs = [bi1, bi2, bi3]
extend_idx = start_idx + 3
while extend_idx + 1 < len(bi_list):
leave_bi = bi_list[extend_idx]
back_bi = bi_list[extend_idx + 1]
if not (leave_bi.is_sure and back_bi.is_sure):
break
if not is_bi_overlap_range(back_bi, zg, zd):
break
bis_for_zs.append(leave_bi)
bis_for_zs.append(back_bi)
extend_idx += 2
if not check_zs_position_filter(last_zs, zg, zd, bis_for_zs):
start_idx += 1
continue
zs_dir = Chan_ZS_DIR.UP if bi1.dir == Chan_BI_DIR.DOWN else Chan_ZS_DIR.DOWN
zs = ChanBIZS(bi1, len(bi_zs_list), zs_dir)
zs.set_zg(zg)
zs.set_zd(zd)
set_zs_bi_list(zs, bis_for_zs)
zs.set_end_bi(bis_for_zs[-1], bis_for_zs[-1].sure_time)
if last_zs:
last_zs.set_next(zs)
zs.set_pre(last_zs)
bi_zs_list.append(zs)
last_zs = zs
start_idx = start_idx + len(bis_for_zs)
# 与 cal_bi_zs_list 一致:最后一笔未确认时末中枢标为未完成;若其后已出现确认的离开笔,仍按离开前最后一笔确认中枢结束
if last_zs:
last_zs.is_sure = bi_list[-1].is_sure
if last_zs and not last_zs.is_sure:
if last_zs.bi_list and len(last_zs.bi_list) > 0:
last_bi_of_zs = last_zs.bi_list[-1]
last_bi_idx = -1
for i, bi in enumerate(bi_list):
if bi == last_bi_of_zs:
last_bi_idx = i
break
has_leave = False
if last_bi_idx >= 0 and last_bi_idx + 1 < len(bi_list):
for i in range(last_bi_idx + 1, len(bi_list)):
bi = bi_list[i]
if bi.is_sure:
leave = (bi.low > last_zs.zg and bi.high > last_zs.zg) or \
(bi.high < last_zs.zd and bi.low < last_zs.zd)
if leave:
has_leave = True
break
if has_leave:
if last_bi_of_zs.is_sure:
last_zs.set_end_bi(last_bi_of_zs, last_bi_of_zs.sure_time)
return bi_zs_list
def find_all_bsp(self, bi_list, bi_zs_list):
"""
笔中枢的三类买卖点识别