diff --git a/__pycache__/ChanBI.cpython-312.pyc b/__pycache__/ChanBI.cpython-312.pyc
index b454148..9b13e87 100644
Binary files a/__pycache__/ChanBI.cpython-312.pyc and b/__pycache__/ChanBI.cpython-312.pyc differ
diff --git a/__pycache__/ChanBSP.cpython-312.pyc b/__pycache__/ChanBSP.cpython-312.pyc
index 177daec..cc05b4c 100644
Binary files a/__pycache__/ChanBSP.cpython-312.pyc and b/__pycache__/ChanBSP.cpython-312.pyc differ
diff --git a/__pycache__/ChanCTime.cpython-312.pyc b/__pycache__/ChanCTime.cpython-312.pyc
index b9efe3f..c08bfc5 100644
Binary files a/__pycache__/ChanCTime.cpython-312.pyc and b/__pycache__/ChanCTime.cpython-312.pyc differ
diff --git a/__pycache__/ChanEnum.cpython-312.pyc b/__pycache__/ChanEnum.cpython-312.pyc
index 0e8de31..60e4aad 100644
Binary files a/__pycache__/ChanEnum.cpython-312.pyc and b/__pycache__/ChanEnum.cpython-312.pyc differ
diff --git a/__pycache__/ChanKLC.cpython-312.pyc b/__pycache__/ChanKLC.cpython-312.pyc
index 9b0f3f5..2436f2e 100644
Binary files a/__pycache__/ChanKLC.cpython-312.pyc and b/__pycache__/ChanKLC.cpython-312.pyc differ
diff --git a/__pycache__/ChanKLU.cpython-312.pyc b/__pycache__/ChanKLU.cpython-312.pyc
index c332c16..0729e0d 100644
Binary files a/__pycache__/ChanKLU.cpython-312.pyc and b/__pycache__/ChanKLU.cpython-312.pyc differ
diff --git a/__pycache__/ChanLun.cpython-312.pyc b/__pycache__/ChanLun.cpython-312.pyc
index 0ff7fa4..334f149 100644
Binary files a/__pycache__/ChanLun.cpython-312.pyc and b/__pycache__/ChanLun.cpython-312.pyc differ
diff --git a/__pycache__/ChanSBI.cpython-312.pyc b/__pycache__/ChanSBI.cpython-312.pyc
index 143d523..39238c4 100644
Binary files a/__pycache__/ChanSBI.cpython-312.pyc and b/__pycache__/ChanSBI.cpython-312.pyc differ
diff --git a/__pycache__/ChanSEG.cpython-312.pyc b/__pycache__/ChanSEG.cpython-312.pyc
index dac2f10..309ff07 100644
Binary files a/__pycache__/ChanSEG.cpython-312.pyc and b/__pycache__/ChanSEG.cpython-312.pyc differ
diff --git a/__pycache__/ChanZS.cpython-312.pyc b/__pycache__/ChanZS.cpython-312.pyc
index c3d3626..db18ccb 100644
Binary files a/__pycache__/ChanZS.cpython-312.pyc and b/__pycache__/ChanZS.cpython-312.pyc differ
diff --git a/web/app.py b/web/app.py
index 3bb3668..1a153c0 100644
--- a/web/app.py
+++ b/web/app.py
@@ -201,8 +201,6 @@ def get_crypto_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time=
print(f"未指定明确时间范围,应用默认限制,返回最新的 {limit} 条记录")
df = df.tail(limit).reset_index(drop=True)
- df = add_indicators(df)
-
# 如果过滤后没有数据,返回None
if len(df) == 0:
print("过滤后无数据")
@@ -290,6 +288,19 @@ def add_indicators(df):
df['ma30'] = (ta.EMA(df, timeperiod=30)).fillna(0)
df['ma250'] = (ta.MA(df, timeperiod=250)).fillna(0)
df['rsi'] = ta.RSI(df, timeperiod=14)
+
+ # 计算布林带 (当前周期 - 20周期,2标准差)
+ bb = ta.BBANDS(df, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0)
+ df['bb_upper'] = bb['upperband'].fillna(0)
+ df['bb_middle'] = bb['middleband'].fillna(0)
+ df['bb_lower'] = bb['lowerband'].fillna(0)
+
+ # 计算次周期布林带 (14周期,2标准差)
+ bb_element = ta.BBANDS(df, timeperiod=14, nbdevup=2.0, nbdevdn=2.0, matype=0)
+ df['element_bb_upper'] = bb_element['upperband'].fillna(0)
+ df['element_bb_middle'] = bb_element['middleband'].fillna(0)
+ df['element_bb_lower'] = bb_element['lowerband'].fillna(0)
+
df['macd'] = df['macd'].fillna(0)
df['macdsignal'] = df['macdsignal'].fillna(0)
df['macdhist'] = df['macdhist'].fillna(0)
@@ -532,25 +543,14 @@ def is_smaller_or_equal_timeframe(tf1, tf2):
return tf1_value <= tf2_value
def clean_dataframe_for_json(df):
- """清理DataFrame中的NaN值,确保JSON序列化正常"""
- # 创建副本以避免修改原数据
- df_clean = df.copy()
+ """清理DataFrame数据用于JSON序列化"""
+ # 创建副本避免修改原始数据
+ clean_df = df.copy()
- # 将NaN、inf、-inf替换为None
- df_clean = df_clean.replace([np.nan, np.inf, -np.inf], None)
+ # 替换NaN值为None
+ clean_df = clean_df.where(pd.notnull(clean_df), None)
- # 处理数值列,确保值为有限数字或None
- numeric_columns = df_clean.select_dtypes(include=[np.number]).columns
- for col in numeric_columns:
- # 确保所有数值都是有限的
- df_clean[col] = df_clean[col].apply(lambda x: x if (x is not None and np.isfinite(x)) else None)
-
- # 处理时间列,确保格式正确
- datetime_columns = df_clean.select_dtypes(include=['datetime64']).columns
- for col in datetime_columns:
- df_clean[col] = df_clean[col].dt.strftime('%Y-%m-%d %H:%M:%S')
-
- return df_clean
+ return clean_df
@app.route('/')
def index():
@@ -615,6 +615,10 @@ def analyze():
# 如果不是只需要分形元素数据,则添加主周期数据
if not elements_only:
print(f"处理主周期数据 (elements_only={elements_only})")
+
+ # 添加技术指标(包括布林带)
+ df = add_indicators(df)
+
# 进行缠论分析
analysis_result = analyze_chan(df)
@@ -661,6 +665,17 @@ def analyze():
'desc': point['desc']
} for point in analysis_result['trade_points']],
'macd': macd_data,
+ # 添加布林带数据
+ 'bollinger': {
+ 'upper': df['bb_upper'].tolist(),
+ 'middle': df['bb_middle'].tolist(),
+ 'lower': df['bb_lower'].tolist()
+ },
+ 'element_bollinger': {
+ 'upper': df['element_bb_upper'].tolist(),
+ 'middle': df['element_bb_middle'].tolist(),
+ 'lower': df['element_bb_lower'].tolist()
+ },
# 添加K线分型信息
'klc_fx_info': [{
'time': format_time_safely(point['time'], client_tz),
@@ -682,6 +697,9 @@ def analyze():
element_df = get_kl_data(symbol, element_timeframe, start_time=start_time, end_time=end_time)
if element_df is not None and len(element_df) > 0:
+ # 添加小周期技术指标(包括布林带)
+ element_df = add_indicators(element_df)
+
# 对小周期数据进行缠论分析
element_analysis = analyze_chan(element_df)
@@ -692,6 +710,18 @@ def analyze():
result['element_timeframe'] = element_timeframe
result['element_macd'] = element_macd_data # 添加小周期MACD数据
+ # 添加小周期布林带数据
+ result['element_bollinger'] = {
+ 'upper': element_df['bb_upper'].tolist(),
+ 'middle': element_df['bb_middle'].tolist(),
+ 'lower': element_df['bb_lower'].tolist()
+ }
+ result['element_element_bollinger'] = {
+ 'upper': element_df['element_bb_upper'].tolist(),
+ 'middle': element_df['element_bb_middle'].tolist(),
+ 'lower': element_df['element_bb_lower'].tolist()
+ }
+
result['element_bi_list'] = [{
'start_time': bi.start_klc.end_time if isinstance(bi.start_klc.end_time, str) else bi.start_klc.end_time.astimezone(client_tz).isoformat(),
'end_time': (bi.end_klc.end_time if isinstance(bi.end_klc.end_time, str) else bi.end_klc.end_time.astimezone(client_tz).isoformat()) if bi.end_klc else None,
@@ -720,7 +750,6 @@ def analyze():
'is_sure': zs.is_sure # 添加中枢是否完成的标志
} for zs in element_analysis['zs_list'] if zs.end_klc]
- # 添加小周期未完成中枢列表
result['element_uncompleted_zs_list'] = [{
'start_time': zs.start_klc.end_time if isinstance(zs.start_klc.end_time, str) else zs.start_klc.end_time.astimezone(client_tz).isoformat(),
'end_time': None, # 未完成中枢没有结束时间
diff --git a/web/templates/index.html b/web/templates/index.html
index e4860b3..ca2a1a1 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -327,7 +327,7 @@
{% endfor %}
-
+
-
+
-
-
-
-
-
-