首次提交

This commit is contained in:
YuWuKunCheng
2026-06-09 20:09:55 +08:00
parent 15a1d43b1d
commit 8405d478bc
11 changed files with 6663 additions and 2 deletions
+698 -2
View File
@@ -138,6 +138,56 @@ def 收集异常信息(exception: Exception, 上下文: dict = None):
return 错误报告
class 图表展示序列(list):
def __init__(self, 观察员: "观察者"):
super().__init__()
self.观察员 = 观察员
self.序号 = 0
self.__类型标识 = None
def append(self, __object):
if self.序号 > 0:
if __object.标识 != self.__类型标识:
...
self.图表刷新(self[-1], sys._getframe().f_lineno)
else:
self.__类型标识 = __object.标识
super().append(__object)
self.图表添加(__object, sys._getframe().f_lineno)
self.序号 += 1
if __object.标识 in ("线段", "线段<线段>"):
if self.观察员 and self.观察员.配置.线段内部中枢图显:
: 虚线 = __object
.合_中枢序列 = 图表展示序列(self.观察员)
.实_中枢序列 = 图表展示序列(self.观察员)
.虚_中枢序列 = 图表展示序列(self.观察员)
def pop(self, __index: SupportsIndex = -1):
弹出 = super().pop(__index)
self.图表移除(弹出, sys._getframe().f_lineno)
self.序号 -= 1
return 弹出
def clear(self) -> None:
self.序号 = 0
super().clear()
def 尾部刷新(self, 行号: int):
if self.序号:
self.图表刷新(self[-1], 行号)
def 图表添加(self, 实线: Union["虚线", "中枢"], 行号: int):
self.观察员 and self.观察员.报信(实线, 指令.添加(实线.标识), 行号)
def 图表移除(self, 实线: Union["虚线", "中枢"], 行号: int):
self.观察员 and self.观察员.报信(实线, 指令.删除(实线.标识), 行号)
def 图表刷新(self, 实线: Union["虚线", "中枢"], 行号: int):
self.观察员 and self.观察员.报信(实线, 指令.修改(实线.标识), 行号)
class 时间周期:
def __init__(self, : int, 是否单笔交易: bool = False):
self._秒 =
@@ -452,6 +502,7 @@ class 观察者(观察者):
if 当前买卖点.买卖点K线.时间戳 not in 活跃时间戳序列:
买卖点序列.add(当前买卖点)
当前买卖点.买卖点K线.买卖点信息.add(当前买卖点.备注)
print(当前买卖点, type(当前买卖点))
self.报信(当前买卖点, 指令.添加(当前买卖点.备注), sys._getframe().f_lineno)
def 图表刷新(self):
@@ -721,6 +772,7 @@ class 观察者(观察者):
@classmethod
def 读取数据文件(cls, 文件路径: str, ws=None, 配置=缠论配置()) -> Self:
# btcusd-300-1631772074-1632222374.nb
print(文件路径)
if "_err-" in str(文件路径):
try:
配置 = 缠论配置.加载配置(str(文件路径).replace(".nb", ".json"))
@@ -741,6 +793,320 @@ class 观察者(观察者):
return 实例
def 识别买卖点(self):
"""
简单买卖策略
"""
if not self.笔序列:
return
if self.分型序列[-1]..序号 + 2 < self.当前缠K.序号:
return
if self.分型序列[-1].强度 not in "强中":
pass
if 笔内部背驰判断(self.普通K线序列, self.笔序列[-1]):
0 and self.添加买卖点("", self.笔序列[-1]., "", "次次级")
if not self.线段序列:
return
# 观察者.判断线段第二买卖点(self.线段序列[-1], self)
if 笔内部背驰判断(self.普通K线序列, self.线段序列[-1]):
0 and self.添加买卖点("", self.线段序列[-1]., "", "次级")
if 线段背驰判断(self.普通K线序列, self.线段序列[-1]):
0 and self.添加买卖点("线段", self.线段序列[-1]., "", "次级")
if dif_三次穿越背离判断(self.普通K线序列, self.线段序列[-1]):
0 and self.添加买卖点("macd_三次穿越", self.线段序列[-1]., "", "次级")
if self.中枢序列:
1 and 观察者.中枢第三买卖点(self.中枢序列[-1], self)
if not self.线段_线段序列:
return
观察者.线段第二买卖点(self.线段_线段序列[-1], self)
观察者.线段第二买卖点(self.线段序列[-1], self)
if 笔内部背驰判断(self.普通K线序列, self.线段_线段序列[-1]):
0 and self.添加买卖点("", self.线段_线段序列[-1]., "", "本级")
return
@classmethod
def 判断线段第二买卖点(cls, : 虚线, 观察员: 观察者):
, , 第三买卖线, _ = 线段.分割序列()
if len() == 2:
符合 = False
# 第一笔 穿越0轴
笔MACD特性 = 虚线.统计MACD行为([0].获取普K序列(观察员), 8, 3)
if [0].方向 is 相对方向.向上 and 笔MACD特性["DEA上穿0"] > 0:
符合 = True
if [0].方向 is 相对方向.向下 and 笔MACD特性["DEA下穿0"] > 0:
符合 = True
# 第二笔 不能穿越0轴
笔MACD特性 = 虚线.统计MACD行为([1].获取普K序列(观察员), 8, 3)
if [1].方向 is 相对方向.向上 and 笔MACD特性["DIF上穿0"] > 0:
符合 = False
if [1].方向 is 相对方向.向下 and 笔MACD特性["DIF下穿0"] > 0:
符合 = False
if 符合:
特征 = "线段二第买卖点"
买卖点分型 = [1].
[1].. and 观察员.添加买卖点(特征, 买卖点分型, "", "次级")
@classmethod
def 笔中枢当前状态(cls, 当前中枢: "中枢", 观察员: "观察者"):
if 当前中枢.标识 != "中枢<笔>":
return None
普K序列: List[K线] = 观察员.普通K线序列
配置 = 观察员.配置
状态 = 当前中枢.当前状态()
进入段: 虚线 = 观察员.笔序列[观察员.笔序列.index(当前中枢.基础序列[0]) - 1]
离开段: 虚线 = 当前中枢.基础序列[-1]
match 状态:
case "中枢之中":
pass
case "中枢之下" | "中枢之上":
if 进入段.方向 is 离开段.方向 and not 相对方向.分析(进入段., 进入段., 离开段., 离开段.).是否包含():
if 背驰分析.MACD背驰(进入段, 离开段, 普K序列) or 虚线.买卖意义(离开段, 观察员)[0]:
特征 = "笔中枢"
买卖点分型 = 离开段.
第几 = "" if ((离开段.方向 is 相对方向.向上 and 当前中枢.高高 <= 离开段.) or (离开段.方向 is 相对方向.向下 and 当前中枢.低低 >= 离开段.)) else ""
观察员.添加买卖点(特征, 买卖点分型, 第几, "同级")
第三买卖线: 虚线 = 当前中枢.第三买卖线
if 第三买卖线:
买卖点分型 = 当前中枢.第三买卖线.
同向均值 = 虚线.武之MACD均值_阴(普K序列, 第三买卖线) if 买卖点分型.结构 in (分型结构., 分型结构.) else 虚线.武之MACD均值_阳(普K序列, 第三买卖线)
# if 同向均值 and 第三买卖线.武之MACD均值 and 第三买卖线.武.与MACD柱子匹配 and 第三买卖线.武.与MACD柱子分型匹配:
if 虚线.买卖意义(第三买卖线, 观察员)[0]:
特征 = "笔中枢"
观察员.添加买卖点(特征, 买卖点分型, "", "同级")
case _:
raise RuntimeError("未知中枢状态", 状态)
@classmethod
def 中枢当前状态(cls, 当前中枢: "中枢", 观察员: "观察者"):
if 当前中枢.标识 != "中枢<线段>":
return None
普K序列: List[K线] = 观察员.普通K线序列
配置 = 观察员.配置
状态 = 当前中枢.当前状态()
买卖点错过误差值 = 配置.买卖点错过误差值
, , 第三买卖线, _ = 线段.分割序列(当前中枢.基础序列[-1], 当前中枢)
match 状态:
case "中枢之中":
"""if not 虚:
if cls.判断线段内部是否背驰(当前中枢[-1], 观察员) and 当前中枢[-1].武.右 and cls.买卖意义(当前中枢[-1], 观察员)[0]:
特征 = "中枢内背驰"
买卖点分型 = 当前中枢[-1].武
观察员.添加买卖点(特征, 买卖点分型, "", "次级")"""
case "中枢之下" | "中枢之上":
if 当前中枢.本级_第三买卖线 is not None: # and len(当前中枢) >= 3 and len(虚) >= 2:
买卖点分型 = None
if 当前中枢.完整性(""):
if 状态 == "中枢之上":
之后缠K序列 = 观察员.缠论K线序列[观察员.缠论K线序列.index(当前中枢.本级_第三买卖线..) :]
之后缠K = None
中枢上轨 = 当前中枢.
if 当前中枢.本级_第三买卖线...标的K线.macd.DIF > 0:
for k in 之后缠K序列:
if k.标的K线.macd.DIF < 0: # 首个下穿0轴
if 之后缠K is None:
之后缠K = k
if 之后缠K:
if k.分型 is 分型结构. and k.标的K线.macd.DIF < 0:
买卖点分型 = 分型.从缠K序列中获取分型(观察员.缠论K线序列, k)
break
else:
# 中枢之下
之后缠K序列 = 观察员.缠论K线序列[观察员.缠论K线序列.index(当前中枢.本级_第三买卖线..) :]
之后缠K = None
中枢下轨 = 当前中枢.
if 当前中枢.本级_第三买卖线...标的K线.macd.DIF < 0:
for k in 之后缠K序列:
if k.标的K线.macd.DIF > 0: # 首个上穿0轴
if 之后缠K is None:
之后缠K = k
if 之后缠K:
if k.分型 is 分型结构. and k.标的K线.macd.DIF > 0:
买卖点分型 = 分型.从缠K序列中获取分型(观察员.缠论K线序列, k)
break
if 买卖点分型:
特征 = "首次穿越0轴"
观察员.添加买卖点(特征, 买卖点分型, "", "本级")
买卖标的值 = 当前中枢.本级_第三买卖线..分型特征值
if 虚线.买卖意义(当前中枢.本级_第三买卖线, 观察员)[0]:
特征 = "中枢段笔"
买卖点分型 = 当前中枢.本级_第三买卖线.
# 观察员.添加买卖点(特征, 买卖点分型, "三", "本级")
else:
# 错过
for 本级_第三买卖线 in 第三买卖线:
if (当前中枢.本级_第三买卖线 is not 本级_第三买卖线) and 虚线.买卖意义(本级_第三买卖线, 观察员)[0] and (买卖标的值 * (1 + 买卖点错过误差值) > 本级_第三买卖线...分型特征值 > 买卖标的值 * (1 - 买卖点错过误差值)):
特征 = "中枢段笔"
买卖点分型 = 本级_第三买卖线.
# 观察员.添加买卖点(特征, 买卖点分型, "三", "错过本级")
break
if 当前中枢.第三买卖线 is None:
# 正在形成第三买卖点?
特征 = 状态
离开段: 虚线 = 当前中枢.基础序列[-1]
"""if not 虚:
# 正在离开中枢
if not 当前中枢.完整性:
pass
else:
pass
if cls.买卖意义(离开段[-1], 观察员)[0] or cls.判断线段内部是否背驰(离开段, 观察员) or cls.买卖意义(离开段[-1], 观察员)[0]:
买卖点分型 = 离开段.武
观察员.添加买卖点(特征, 买卖点分型, "", "同级")
else:
# 即将到来的 同级第三买卖点!
if (离开段.方向 is 相对方向.向下 and 虚[-1].武.分型特征值 < 离开段.文.分型特征值) or (离开段.方向 is 相对方向.向上 and 虚[-1].武.分型特征值 > 离开段.文.分型特征值):
# 一笔突破当前线段起点
if cls.买卖意义(虚[-1], 观察员)[0]:
买卖点分型 = 虚[-1].武
观察员.添加买卖点(特征, 买卖点分型, "", "次次级")"""
else:
# 第三买卖点已出现,可能的情况如下
# 1.不当前中枢有任何的交集
# 2.有交集
# 1.与中枢 中高 中低 发生重叠
# 2.与中枢 高高 高低 发生重叠
# 3.失败重新进入当前中枢
# 重点就是第三点,如何判断会回到中枢?
# 提出完整性的概念,最后离开段中内部中枢是否脱离中枢区间
if not 当前中枢.完整性(""):
return 状态, "不完整"
# if 当前中枢.第三买卖线.武 is not 观察员.分型序列[-1]:
# return 状态, ""
特征 = "中枢段"
assert 相对方向.分析(当前中枢., 当前中枢., 当前中枢.第三买卖线., 当前中枢.第三买卖线.).是否缺口()
普K序列 = 当前中枢.第三买卖线.获取普K序列(观察员.观察员)
MACD特性 = 虚线.统计MACD行为(普K序列, 8, 3)
if MACD特性["DEA上穿0"] > 0 and MACD特性["DEA下穿0"] > 0:
特征 = "中枢段_DEA穿越2"
买卖点分型 = 当前中枢.第三买卖线.
观察员.添加买卖点(特征, 买卖点分型, "", "同级")
if 当前中枢.基础序列[-1].合_中枢序列 and 当前中枢.基础序列[-1].合_中枢序列[-1].基础序列[-1] is 当前中枢.第三买卖线.基础序列[-1]:
pass # return 状态, "前合中枢,线段首次形成"
if 线段.判断线段内部是否背驰(当前中枢.第三买卖线, 观察员): # or 阳[-1]. 买卖意义[0]:
买卖点分型 = 当前中枢.第三买卖线.
# 观察员.添加买卖点(特征, 买卖点分型, "三", "同级")
else:
return 状态, "同级,内部非背驰"
case _:
raise RuntimeError("未知中枢状态", 状态)
@classmethod
def 中枢第三买卖点(cls, 当前中枢: "中枢", 观察员: "观察者"):
if 当前中枢.标识 != "中枢<线段>":
return None
状态 = 当前中枢.当前状态()
if 状态 == "中枢之中":
return None
, , 第三买卖线, _ = 线段.分割序列(当前中枢.基础序列[-1], 当前中枢)
if 当前中枢.本级_第三买卖线 is None:
return None
买卖点分型 = None
if 当前中枢.完整性(""):
之后缠K序列 = 观察员.缠论K线序列[观察员.缠论K线序列.index(当前中枢.本级_第三买卖线..) :]
之后缠K = None
assert 之后缠K序列[0] is 当前中枢.本级_第三买卖线.., (之后缠K序列[0], 当前中枢.本级_第三买卖线..)
if 状态 == "中枢之上":
中枢上轨 = 当前中枢.
if 当前中枢.本级_第三买卖线...标的K线.macd.DIF > 0:
for k in 之后缠K序列:
if k.标的K线.macd.DIF < 0: # 首个下穿0轴
if 之后缠K is None:
之后缠K = k
if 之后缠K:
if k.分型 is 分型结构. and k.标的K线.macd.DIF < 0:
买卖点分型 = 分型.从缠K序列中获取分型(观察员.缠论K线序列, k)
break
else:
# 中枢之下
中枢下轨 = 当前中枢.
if 当前中枢.本级_第三买卖线...标的K线.macd.DIF < 0:
for k in 之后缠K序列:
if k.标的K线.macd.DIF > 0: # 首个上穿0轴
if 之后缠K is None:
之后缠K = k
if 之后缠K:
if k.分型 is 分型结构. and k.标的K线.macd.DIF > 0:
买卖点分型 = 分型.从缠K序列中获取分型(观察员.缠论K线序列, k)
break
if 买卖点分型:
特征 = "首次穿越0轴"
观察员.添加买卖点(特征, 买卖点分型, "", "本级")
if 当前中枢.第三买卖线 is None:
return None
if not 当前中枢.完整性(""):
return None
特征 = "中枢段"
assert 相对方向.分析(当前中枢., 当前中枢., 当前中枢.第三买卖线., 当前中枢.第三买卖线.).是否缺口()
普K序列 = 当前中枢.第三买卖线.获取普K序列(观察员.观察员)
MACD特性 = 虚线.统计MACD行为(普K序列, 8, 3)
if MACD特性["DEA上穿0"] > 0 and MACD特性["DEA下穿0"] > 0:
特征 = "中枢段_DEA穿越2"
买卖点分型 = 当前中枢.第三买卖线.
观察员.添加买卖点(特征, 买卖点分型, "", "同级")
@classmethod
def 线段第二买卖点(cls, 当前线段: "虚线", 观察员: "观察者"):
if 当前线段.标识 not in ("线段<线段>", "线段"):
return
, , _, _ = 线段.分割序列(当前线段, None)
if len() != 2:
return
(, ) =
首_MACD信息 = 虚线.统计MACD行为(.获取普K序列(观察员))
if .方向 is 相对方向.向下 and 首_MACD信息["DEA下穿0"] >= 1:
pass
elif .方向 is 相对方向.向上 and 首_MACD信息["DEA上穿0"] >= 1:
pass
else:
return
买卖点分型 = None
尾_MACD信息 = 虚线.统计MACD行为(.获取普K序列(观察员))
if .方向 is 相对方向.向下 and 首_MACD信息["DEA下穿0"] >= 1:
买卖点分型 = .
elif .方向 is 相对方向.向上 and 首_MACD信息["DEA上穿0"] >= 1:
买卖点分型 = .
else:
return
if not 买卖点分型:
return
特征 = f"{当前线段.标识}第二"
观察员.添加买卖点(特征, 买卖点分型, "", "同级")
__代码执行器_全局声明__ = dir()
@@ -767,6 +1133,283 @@ def 随机配置(随机源: Optional[random.Random] = None):
)
def dif_三次穿越背离判断(K线序列: List["K线"], : 虚线) -> bool:
"""
基于 DIF 线穿越零轴的三次穿越背离判断,第三次穿越后检查 MACD 柱。
向下模式:
1. 第一次穿越:DIF 从正 → 负(下穿0轴)
2. 第二次穿越:DIF 从负 → 正(上穿0轴),且上穿后的最高价 ≤ 第一次下穿前的最高价
3. 第三次穿越:DIF 从正 → 负(再次下穿0轴)
检查第三次穿越后的连续 MACD 负值段内,
价格最低点对应的 MACD 柱值 < 该段 MACD 柱最大值 → 返回 True
向上模式(对称):
1. 第一次穿越:DIF 从负 → 正(上穿0轴)
2. 第二次穿越:DIF 从正 → 负(下穿0轴),且下穿后的最低价 ≥ 第一次上穿前的最低价
3. 第三次穿越:DIF 从负 → 正(再次上穿0轴)
检查第三次穿越后的连续 MACD 正值段内,
价格最高点对应的 MACD 柱值 < 该段 MACD 柱最大值 → 返回 True
参数:
k线序列: K线对象列表,需包含 .close, .macd.DIF, .macd.MACD柱
方向: "向下""向上"
返回:
bool: 满足背离条件返回 True,否则 False
"""
方向 = "向上" if .方向.是否向上() else "向下"
k线序列: List[K线] = K线.截取(K线序列, ...标的K线, ...标的K线)
if len(k线序列) < 4:
return False
dif_vals = [k.macd.DEA for k in k线序列]
macd_vals = [k.macd.MACD柱 for k in k线序列]
# 1. 找出所有 DIF 穿越零轴的点
穿越点 = [] # (索引, 方向)
for i in range(1, len(dif_vals)):
prev, curr = dif_vals[i - 1], dif_vals[i]
if prev * curr < 0:
if prev > 0 and curr < 0:
穿越点.append((i, "下穿"))
elif prev < 0 and curr > 0:
穿越点.append((i, "上穿"))
if len(穿越点) < 3:
return False
# 2. 根据方向寻找连续符合顺序的三次穿越
期望序列 = ["下穿", "上穿", "下穿"] if 方向 == "向下" else ["上穿", "下穿", "上穿"]
found = None
for j in range(len(穿越点) - 2):
if 穿越点[j][1] == 期望序列[0] and 穿越点[j + 1][1] == 期望序列[1] and 穿越点[j + 2][1] == 期望序列[2]:
found = (穿越点[j][0], 穿越点[j + 1][0], 穿越点[j + 2][0])
break
if not found:
return False
idx1, idx2, idx3 = found
# 3. 向下模式
if 方向 == "向下":
# 条件2:第二次上穿后的最高价 <= 第一次下穿前的最高价
before = k线序列[:idx1]
if not before:
return False
max_before = max(k. for k in before)
after = k线序列[idx2:]
if not after:
return False
max_after = max(k. for k in after)
if max_after > max_before:
return False
# 第三次穿越后,取连续 MACD 负值段
segment = []
for i in range(idx3, len(macd_vals)):
if macd_vals[i] < 0:
segment.append(k线序列[i])
else:
break
if len(segment) < 2:
return False
# 段内最低价及其对应的 MACD 柱值
min_price = float("inf")
min_macd = None
for k in segment:
if k. < min_price:
min_price = k.
min_macd = k.macd.MACD柱
max_macd = max(k.macd.MACD柱 for k in segment)
return min_macd < max_macd
# 4. 向上模式
else:
# 条件2:第二次下穿后的最低价 >= 第一次上穿前的最低价
before = k线序列[:idx1]
if not before:
return False
min_before = min(k. for k in before)
after = k线序列[idx2:]
if not after:
return False
min_after = min(k. for k in after)
if min_after < min_before:
return False
# 第三次穿越后,取连续 MACD 正值段
segment = []
for i in range(idx3, len(macd_vals)):
if macd_vals[i] > 0:
segment.append(k线序列[i])
else:
break
if len(segment) < 2:
return False
# 段内最高价及其对应的 MACD 柱值
max_price = -float("inf")
max_macd = None
for k in segment:
if k. > max_price:
max_price = k.
max_macd = k.macd.MACD柱
max_macd_in_seg = max(k.macd.MACD柱 for k in segment)
return max_macd < max_macd_in_seg
def 找首个MACD交叉前后K线(k线序列: List["K线"], 起始K线: "K线") -> Tuple[Optional["K线"], Optional["K线"]]:
"""
在K线序列中,从起始K线之后查找第一个MACD快慢线交叉点(金叉或死叉),
返回交叉点前一根K线和后一根K线。若未找到,返回(None, None)。
参数:
k线序列: K线对象列表,按时间顺序排列
起始K线: 开始查找的位置
"""
# 定位起始索引
try:
start_idx = k线序列.index(起始K线)
except ValueError:
return None, None
# 从起始K线的下一根开始,到倒数第二根结束(需要比较前后两根)
for i in range(start_idx, len(k线序列) - 1):
prev = k线序列[i]
curr = k线序列[i + 1]
# 获取DIF和DEA值,若存在None则跳过
dif_prev = prev.macd.DIF
dea_prev = prev.macd.DEA
dif_curr = curr.macd.DIF
dea_curr = curr.macd.DEA
if None in (dif_prev, dea_prev, dif_curr, dea_curr):
continue
# 金叉:前一根 DIF <= DEA,后一根 DIF > DEA
if dif_prev <= dea_prev and dif_curr > dea_curr:
return prev, curr
# 死叉:前一根 DIF >= DEA,后一根 DIF < DEA
if dif_prev >= dea_prev and dif_curr < dea_curr:
return prev, curr
return None, None
def 计算MACD柱子分段(k线序列: Sequence["K线"] = None) -> Tuple[List[List["K线"]], ...]:
if not k线序列:
return ()
def 符号(x: float) -> str:
if x > 0:
return ""
else:
return ""
当前符号 = 符号(k线序列[0].macd.MACD柱)
当前段柱子 = [k线序列[0]]
结果 = []
for i in range(1, len(k线序列)):
新符号 = 符号(k线序列[i].macd.MACD柱)
if 新符号 == 当前符号:
当前段柱子.append(k线序列[i])
else:
结果.append(当前段柱子)
当前段柱子 = [k线序列[i]]
当前符号 = 新符号
if 当前段柱子:
结果.append(当前段柱子)
= []
= []
for 序列 in 结果:
if 序列[-1].macd.MACD柱 > 0:
.append(序列)
else:
.append(序列)
return ,
def 笔内部背驰判断(K线序列: List[K线], 当前笔: 虚线) -> bool:
"""
基于笔内部MACD柱的分段能量变化,判断是否发生内部背驰(端点可能转折)。
返回 True 表示出现内部背驰信号。
"""
klines: List[K线] = K线.截取(K线序列, 当前笔...标的K线, 当前笔...标的K线) # 笔对象本身可迭代返回K线
if len(klines) < 3:
return False
正段, 负段 = 计算MACD柱子分段(klines)
# 按笔的方向选择相关段(向上笔看正段,向下笔看负段)
if 当前笔.方向 == 相对方向.向上:
相关段 = 正段
else:
相关段 = 负段
if len(相关段) < 2:
return False
# 计算每段的能量(代数和)
能量 = [sum(k.macd.MACD柱 for k in seg) for seg in 相关段]
# 计算每段末端价格(向上笔用最高价,向下笔用最低价)
if 当前笔.方向 == 相对方向.向上:
末端价格 = [seg[-1]. for seg in 相关段]
# 价格必须逐段抬高,能量逐段减小
return all(末端价格[i] < 末端价格[i + 1] for i in range(len(末端价格) - 1)) and all(能量[i] > 能量[i + 1] for i in range(len(能量) - 1))
else:
末端价格 = [seg[-1]. for seg in 相关段]
# 价格必须逐段降低,能量绝对值逐段减小
return all(末端价格[i] > 末端价格[i + 1] for i in range(len(末端价格) - 1)) and all(abs(能量[i]) > abs(能量[i + 1]) for i in range(len(能量) - 1))
def 线段背驰判断(k线序列: List[K线], : 虚线) -> bool:
"""线段内部背驰(比较最后一个中枢的进入段和离开段)"""
if not .合_中枢序列:
return False
zs = .合_中枢序列[-1] # 最后一个中枢
# 中枢由三笔构成:左、中、右(方向交替)
进入笔 = None
离开笔 = None
# 找到中枢之前的同向笔
for bi in reversed(.笔序列[: .笔序列.index(zs.基础序列[0])]):
if bi.方向 == zs.基础序列[0].方向:
进入笔 = bi
break
# 找到中枢之后的同向笔
for bi in .笔序列[.笔序列.index(zs.基础序列[-1]) + 1 :]:
if bi.方向 == zs.基础序列[0].方向:
离开笔 = bi
break
if 进入笔 is None or 离开笔 is None:
return False
# 价格条件
if zs.基础序列[0].方向 == 相对方向.向上:
if 离开笔. <= 进入笔.:
return False
else:
if 离开笔. >= 进入笔.:
return False
# 力度比较(MACD面积)
return 背驰分析.MACD背驰(离开笔, 进入笔, k线序列)
class 笔K线生成配置(BaseModel):
"""笔的K线生成配置"""
@@ -1255,7 +1898,7 @@ def 从序列中机选(
def 根据当前K线生成新K线(self, 方向: 相对方向, 居中: bool = False) -> "K线":
时间偏移 = timedelta(seconds=self.周期)
时间戳: datetime = self.时间戳 + 时间偏移
时间戳: datetime = self.时间戳 + self.周期 # 时间偏移
成交量: float = 998
: float = 0
: float = 0
@@ -1534,6 +2177,7 @@ def 同步_跟踪回测(观察员: 观察者, 数据源: bt.feed.DataBase):
def 测试_读取数据(symbol: str = "btcusd", limit: int = 500, freq: SupportsInt = 时间周期.(5), ws: Optional[WebSocket] = None, 配置: 缠论配置 = 缠论配置(线段内部中枢图显=False), 文件路径: str = "./templates/btcusd_ex-1800-1685795400-1713488400.nb"):
def 魔法():
启动时间 = datetime.now()
print(观察者)
观察员 = 观察者.读取数据文件(配置.加载文件路径, ws, 配置)
# 观察员.分部分析()
消耗用时 = datetime.now() - 启动时间
@@ -1935,7 +2579,8 @@ async def 处理图表消息(用户标识: str, 消息字典: Dict, websocket: W
config = 消息字典.get("config", dict())
当前配置 = 缠论配置.from_dict(config)
print(当前配置.to_dict())
差异 = 缠论配置().对比(当前配置)
print(差异)
配置组 = 缠论配置.按序号重组字典(当前配置, config)
print(配置组)
@@ -2231,7 +2876,58 @@ async def 主页(
)
def 测试_读取数据2(配置: 缠论配置):
"""测试_读取数据
:param 配置: 缠论配置
:return: 测试函数
"""
def 魔法():
启动时间 = datetime.now()
观察员 = 观察者.读取数据文件(配置.加载文件路径, 配置)
消耗用时 = datetime.now() - 启动时间
print("测试_读取数据 耗时", 消耗用时, "普K数量", len(观察员.普通K线序列))
return 观察员
return 魔法
def 测试_周期合成2(配置: 缠论配置, 配置组: Dict[int, 缠论配置] = dict()):
"""测试_周期合成
:param 配置: 默认配置
:param 配置组: 各周期独立配置
:return: 测试函数
"""
文件路径 = 配置.加载文件路径
name = Path(文件路径).name.split(".")[0]
符号, 周期, 起始时间戳, 结束时间戳 = name.split("-")
周期 = int(周期)
周期组 = [周期, 周期 * 5, 周期 * 5 * 6]
def 魔法():
启动时间 = datetime.now()
多级别分析 = 立体分析器(符号, 周期组, 配置, 配置组)
with open(文件路径, "rb") as f:
buffer = f.read()
size = struct.calcsize(">6d")
for i in range(len(buffer) // size):
k线 = K线.读取大端字节数组(buffer[i * size : i * size + size], 周期, 符号)
多级别分析.投喂K线(k线)
消耗用时 = datetime.now() - 启动时间
print("测试_周期合成", 消耗用时, "普K数量", len(多级别分析._单体分析器[周期].普通K线序列))
return 多级别分析
return 魔法
if __name__ == "__main__":
当前配置 = 缠论配置.不推送()
当前配置.加载文件路径 = str(Path(__file__).parent / "btcusd-300-1761327300-1776327900.nb")
测试_读取数据(配置=当前配置)() # .测试_保存数据()
# 测试_周期合成(当前配置)().测试_保存数据()
if __name__ == "__ma2in__":
def 运行单个回测(线程编号: int):
"""单个线程执行的函数,内部捕获异常以免影响其他线程"""