change something

This commit is contained in:
jackyu66git
2025-04-27 18:37:50 +08:00
parent 88701608bd
commit fceb57d2b8
10 changed files with 285 additions and 162 deletions
+2
View File
@@ -1,3 +1,5 @@
.DS_Store .DS_Store
__pycache__/ __pycache__/
strategies/__pycache__/ strategies/__pycache__/
/__pycache__
*.pyc
+3
View File
@@ -1,3 +1,4 @@
from decimal import Decimal
import ChanKLC import ChanKLC
from ChanEnum import Chan_BI_DIR from ChanEnum import Chan_BI_DIR
class ChanBI(): class ChanBI():
@@ -81,6 +82,8 @@ class ChanBI():
self.cal_macd_div() self.cal_macd_div()
def append_klc_list(self, klc_list): def append_klc_list(self, klc_list):
self.klc_list.append(klc_list) self.klc_list.append(klc_list)
def get_decimal(self, value):
return Decimal("{:.2f}".format(value))
def update_bi(self, klc): def update_bi(self, klc):
self.end_klc = None self.end_klc = None
if self.dir == Chan_BI_DIR.UP and klc.high > self.high: if self.dir == Chan_BI_DIR.UP and klc.high > self.high:
+9 -44
View File
@@ -25,35 +25,14 @@ class ChanKLC():
self.open = klu.open self.open = klu.open
self.close = klu.close self.close = klu.close
self.volume = klu.volume self.volume = klu.volume
self.macdhist = 0
self.bi_macdhist = 0
self.bi_macd_div = 0.0
self.bi = None self.bi = None
self.distance = 0 self.distance = 0
self.klc_fx_type = Chan_KLC_FX.UNKNOWN self.klc_fx_type = Chan_KLC_FX.UNKNOWN
self.rsi = klu.rsi
self.volume_ratio = klu.volume_ratio
def set_klc_fx_type(self, klc_fx_type): def set_klc_fx_type(self, klc_fx_type):
#print(self.start_time, klc_fx_type, self.get_feature_data()['klu_macd'], self.get_feature_data()['klu_macdhist'], self.get_feature_data()['klu_rsi']) #print(self.start_time, klc_fx_type, self.get_feature_data()['klu_macd'], self.get_feature_data()['klu_macdhist'], self.get_feature_data()['klu_rsi'])
if self.check_klc_fx_type(klc_fx_type):
self.klc_fx_type = klc_fx_type self.klc_fx_type = klc_fx_type
self.klc_fx_type = klc_fx_type
def check_klc_fx_type(self, klc_fx_type):
if klc_fx_type == Chan_KLC_FX.BOTTOM1:
features = self.cal_klu_features()
if features['klu_macd'] > 0:
#print(self.start_time, klc_fx_type, features['klu_macd'])
return False
else:
return True
elif klc_fx_type == Chan_KLC_FX.TOP1:
features = self.get_feature_data()
if features['klu_macd'] < 0:
#print(self.start_time, klc_fx_type, features['klu_macd'])
return False
else:
return True
else:
return True
def add_klu(self, klu): def add_klu(self, klu):
self.klus.append(klu) self.klus.append(klu)
def set_end_klu(self, klu): def set_end_klu(self, klu):
@@ -62,6 +41,10 @@ class ChanKLC():
self.close = klu.close self.close = klu.close
for index in range(1, len(self.klus)): for index in range(1, len(self.klus)):
self.volume += self.klus[index].volume self.volume += self.klus[index].volume
self.rsi += self.klus[index].rsi
self.volume_ratio += self.klus[index].volume_ratio
self.rsi = self.rsi / len(self.klus)
self.volume_ratio = self.volume_ratio / len(self.klus)
def set_next(self, klc): def set_next(self, klc):
self.next = klc self.next = klc
def set_pre(self, klc): def set_pre(self, klc):
@@ -138,27 +121,7 @@ class ChanKLC():
return Chan_FX_TYPE.UNKNOWN return Chan_FX_TYPE.UNKNOWN
def set_bi(self, bi): def set_bi(self, bi):
self.bi = bi self.bi = bi
self.get_macdhist()
for index in range(0, len(self.bi.klc_list)):
klc = self.bi.klc_list[index]
if klc.index == self.index:
break
else:
if bi.dir == Chan_BI_DIR.UP and klc.get_macdhist() > 0:
self.bi_macdhist += klc.get_macdhist()
elif bi.dir == Chan_BI_DIR.DOWN and klc.get_macdhist() < 0:
self.bi_macdhist -= klc.get_macdhist()
self.distance = self.index - bi.start_klc.index self.distance = self.index - bi.start_klc.index
if False:
if bi.is_sure:
print(self.start_time, self.distance, bi.index, bi.start_time, bi.dir, bi.end_time)
else:
print(self.start_time, self.distance, bi.index, bi.start_time, bi.dir)
def get_macdhist(self):
self.macdhist = 0
for klu in self.klus:
self.macdhist += klu.macdhist
return self.macdhist
def cal_klu_features(self): def cal_klu_features(self):
features = dict() features = dict()
feature_sums = dict() feature_sums = dict()
@@ -196,6 +159,8 @@ class ChanKLC():
features['klc_pre_pre_fx'] = (0 if self.pre.pre.fx == Chan_FX_TYPE.UNKNOWN else 1 if self.pre.pre.fx == Chan_FX_TYPE.TOP else 2) if self.pre and self.pre.pre else 0 #11 features['klc_pre_pre_fx'] = (0 if self.pre.pre.fx == Chan_FX_TYPE.UNKNOWN else 1 if self.pre.pre.fx == Chan_FX_TYPE.TOP else 2) if self.pre and self.pre.pre else 0 #11
features['klc_pre_pre_pre_fx'] = (0 if self.pre.pre.pre.fx == Chan_FX_TYPE.UNKNOWN else 1 if self.pre.pre.pre.fx == Chan_FX_TYPE.TOP else 2) if self.pre and self.pre.pre and self.pre.pre.pre else 0 #12 features['klc_pre_pre_pre_fx'] = (0 if self.pre.pre.pre.fx == Chan_FX_TYPE.UNKNOWN else 1 if self.pre.pre.pre.fx == Chan_FX_TYPE.TOP else 2) if self.pre and self.pre.pre and self.pre.pre.pre else 0 #12
features['klc_distance'] = self.distance #13 features['klc_distance'] = self.distance #13
features['klc_volume_ratio'] = self.volume_ratio #14
features['klc_rsi'] = self.rsi #15
# New Add 20250422 # New Add 20250422
#features['klc_macdhist'] = self.get_macdhist() #11 #features['klc_macdhist'] = self.get_macdhist() #11
#features['klc_bi_macdhist'] = self.bi_macdhist #12 #features['klc_bi_macdhist'] = self.bi_macdhist #12
@@ -492,6 +457,6 @@ class ChanKLC():
features['klc_is_inner_inclusive'] = 0 features['klc_is_inner_inclusive'] = 0
# 从KLU获取其他特征 # 从KLU获取其他特征
features.update(self.cal_klu_features()) #features.update(self.cal_klu_features())
return features return features
+3
View File
@@ -18,6 +18,7 @@ class ChanKLU:
self.ma30 = 0 self.ma30 = 0
self.ma250 = 0 self.ma250 = 0
self.rsi = 0 self.rsi = 0
self.volume_ratio = 0
def set_idx(self, idx): def set_idx(self, idx):
self.idx = idx self.idx = idx
self.index = idx self.index = idx
@@ -30,6 +31,7 @@ class ChanKLU:
self.ma30 = float(item['ma30']) if item['ma30'] else 0 self.ma30 = float(item['ma30']) if item['ma30'] else 0
self.ma250 = float(item['ma250']) if item['ma250'] else 0 self.ma250 = float(item['ma250']) if item['ma250'] else 0
self.rsi = float(item['rsi']) if item['rsi'] else 0 self.rsi = float(item['rsi']) if item['rsi'] else 0
self.volume_ratio = float(item['volume_ratio']) if item['volume_ratio'] else 0
def get_feature_data(self): def get_feature_data(self):
features = dict() features = dict()
features['klu_close'] = self.close features['klu_close'] = self.close
@@ -46,4 +48,5 @@ class ChanKLU:
features['klu_ma30'] = self.ma30 features['klu_ma30'] = self.ma30
features['klu_ma250'] = self.ma250 features['klu_ma250'] = self.ma250
features['klu_rsi'] = self.rsi features['klu_rsi'] = self.rsi
features['klu_volume_ratio'] = self.volume_ratio
return features return features
+28 -5
View File
@@ -80,8 +80,8 @@ class ChanLun():
return Chan_FX_TYPE.UNKNOWN return Chan_FX_TYPE.UNKNOWN
def get_macd(self, df): def get_macd(self, df):
fast = 8 fast = 8
slow = 16 slow = 15
period = 6 period = 2
macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period) macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period)
df['macd'] = macd['macd'] df['macd'] = macd['macd']
df['macdsignal'] = macd['macdsignal'] df['macdsignal'] = macd['macdsignal']
@@ -212,6 +212,27 @@ class ChanLun():
klc_list = self.get_klc_list(dataframe) klc_list = self.get_klc_list(dataframe)
bi_list = self.cal_bi_list(klc_list) bi_list = self.cal_bi_list(klc_list)
return klc_list return klc_list
def print_bi_klc(self, dataframe):
klc_list = self.get_klc_list(dataframe)
bi_list = self.cal_bi_list(klc_list)
rsi_list = dataframe['rsi']
fx_list = []
for klc in klc_list:
if klc.klc_fx_type != Chan_KLC_FX.UNKNOWN:
if klc.bi.dir == Chan_BI_DIR.UP and klc.volume_ratio > 2:
print(klc.start_time, klc.end_time, klc.klc_fx_type, klc.rsi, klc.volume_ratio)
fx_list.append(klc)
elif klc.bi.dir == Chan_BI_DIR.DOWN and klc.volume_ratio > 2:
print(klc.start_time, klc.end_time, klc.klc_fx_type, klc.rsi, klc.volume_ratio)
fx_list.append(klc)
bi_start_index_list = []
for bi in bi_list:
bi_start_index_list.append(bi.start_klc.index)
if bi.end_klc:
bi.cal_macdhist()
bi.cal_macd_div()
print("Bi:", bi.start_time, bi.end_time, bi.dir, bi.macd_hist, bi.macd_div)
klc_index_count = 0
def get_seg_list(self, bi_list): def get_seg_list(self, bi_list):
seg_list = [] seg_list = []
up_bi_list = [] up_bi_list = []
@@ -639,6 +660,7 @@ class ChanLun():
#print(klc.start_time, last_bi.start_klc.start_time, "New TOP Found reset last bi") #print(klc.start_time, last_bi.start_klc.start_time, "New TOP Found reset last bi")
klc.set_state("10") klc.set_state("10")
#print(klc.start_time, klc.fx, "笔卖点Sell 1") #print(klc.start_time, klc.fx, "笔卖点Sell 1")
klc.set_klc_fx_type(Chan_KLC_FX.TOP2)
bi_list[-1].add_klc(klc) bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1]) klc.set_bi(bi_list[-1])
else: else:
@@ -758,6 +780,7 @@ class ChanLun():
#print(klc.start_time, last_bi.start_klc.start_time, "New BOTTOM Found reset last bi") #print(klc.start_time, last_bi.start_klc.start_time, "New BOTTOM Found reset last bi")
#klc.set_state("-10") #klc.set_state("-10")
#print(klc.start_time, klc.fx, "笔买点Buy 1") #print(klc.start_time, klc.fx, "笔买点Buy 1")
klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM2)
bi_list[-1].add_klc(klc) bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1]) klc.set_bi(bi_list[-1])
else: else:
@@ -1903,10 +1926,10 @@ class ChanLun():
bbox=dict(boxstyle="round,pad=0.2", fc=style['color'], alpha=0.5)) bbox=dict(boxstyle="round,pad=0.2", fc=style['color'], alpha=0.5))
""" """
# 绘制MACD(使用小周期数据) # 绘制MACD(使用小周期数据)
exp1 = small_df['close'].ewm(span=8, adjust=False).mean() exp1 = small_df['close'].ewm(span=12, adjust=False).mean()
exp2 = small_df['close'].ewm(span=16, adjust=False).mean() exp2 = small_df['close'].ewm(span=26, adjust=False).mean()
macd = exp1 - exp2 macd = exp1 - exp2
signal = macd.ewm(span=6, adjust=False).mean() signal = macd.ewm(span=9, adjust=False).mean()
histogram = macd - signal histogram = macd - signal
ax3.bar(small_dates_num, histogram, width=0.0002, color=['red' if h > 0 else 'green' for h in histogram]) ax3.bar(small_dates_num, histogram, width=0.0002, color=['red' if h > 0 else 'green' for h in histogram])
+2 -3
View File
@@ -288,7 +288,6 @@ class ChanLunClassifier:
# 使用ChanLun获取bi_list # 使用ChanLun获取bi_list
klc_list = self.chan.get_klc_list(dataframe) klc_list = self.chan.get_klc_list(dataframe)
bi_list = self.chan.cal_bi_list(klc_list) bi_list = self.chan.cal_bi_list(klc_list)
seg_list = self.chan.get_seg_list(bi_list)
# 筛选方向为UP的bi的起始klc # 筛选方向为UP的bi的起始klc
feature_data = [] feature_data = []
labels = [] labels = []
@@ -312,7 +311,6 @@ class ChanLunClassifier:
# 保存第一个样本的特征名称,用于CSV列名 # 保存第一个样本的特征名称,用于CSV列名
if len(feature_keys) == 0: if len(feature_keys) == 0:
feature_keys = list(features.keys()) feature_keys = list(features.keys())
# 将特征转换为模型可用的格式 # 将特征转换为模型可用的格式
feature_vec = [] feature_vec = []
for key, value in features.items(): for key, value in features.items():
@@ -335,7 +333,8 @@ class ChanLunClassifier:
feature_data.append(feature_vec) feature_data.append(feature_vec)
labels.append(label) labels.append(label)
for index, key in enumerate(feature_keys):
print(index, key, feature_data[0][index])
# 如果需要保存到CSV # 如果需要保存到CSV
if save_csv: if save_csv:
# 创建DataFrame保存特征数据 # 创建DataFrame保存特征数据
+16 -3
View File
@@ -117,6 +117,8 @@ class ChanLun_SOL_15(IStrategy):
#self.print_macd_div_list(dataframe) #self.print_macd_div_list(dataframe)
#self.print_resample_df(dataframe, 1, 50) #self.print_resample_df(dataframe, 1, 50)
#self.chan.get_bi_list(dataframe_30) #self.chan.get_bi_list(dataframe_30)
#self.chan.plot_dual(dataframe_5, dataframe_30)
self.chan.print_bi_klc(dataframe_5)
#if self.last_time + timedelta(minutes=1) < datetime.now(): #if self.last_time + timedelta(minutes=1) < datetime.now():
#print(informative.iloc[-1]) #print(informative.iloc[-1])
#self.print_klc(dataframe, "1m: ") #self.print_klc(dataframe, "1m: ")
@@ -279,10 +281,11 @@ class ChanLun_SOL_15(IStrategy):
cn3 = 'resample_{}_state'.format(self.get_ticker_indicator()*time) cn3 = 'resample_{}_state'.format(self.get_ticker_indicator()*time)
logger.info(f'{df[cn1][index]}, {df[cn2][index]}, {df[cn3][index]}') logger.info(f'{df[cn1][index]}, {df[cn2][index]}, {df[cn3][index]}')
def add_indicators(self, df): def add_indicators(self, df):
fast = 9 fast = 8
slow = 24 slow = 16
period = 14 period = 6
macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period) macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period)
df['macd'] = macd['macd'] df['macd'] = macd['macd']
df['macdsignal'] = macd['macdsignal'] df['macdsignal'] = macd['macdsignal']
df['macdhist'] = macd['macdhist'] df['macdhist'] = macd['macdhist']
@@ -299,7 +302,17 @@ class ChanLun_SOL_15(IStrategy):
df['ma30'] = df['ma30'].fillna(0) df['ma30'] = df['ma30'].fillna(0)
df['ma250'] = df['ma250'].fillna(0) df['ma250'] = df['ma250'].fillna(0)
df['rsi'] = df['rsi'].fillna(0) df['rsi'] = df['rsi'].fillna(0)
df['volume_ratio'] = self.cal_volume_ratio(df)
return df return df
def cal_volume_ratio(self, dataframe, window=10):
df = dataframe.copy()
# 计算过去N根K线的平均成交量
df['avg_volume'] = df['volume'].rolling(window=window).mean()
# 计算量比
df['volume_ratio'] = df['volume'] / df['avg_volume']
# 填充缺失值(前N根K线)
df['volume_ratio'] = df['volume_ratio'].fillna(1.0)
return df['volume_ratio']
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[ dataframe.loc[
+21 -11
View File
@@ -115,9 +115,9 @@ class ChanLun_SOL_5(IStrategy):
self.classifier.train_model(dataframe, model_name="1m_model") self.classifier.train_model(dataframe, model_name="1m_model")
self.classifier.train_model(dataframe_1d, model_name="1d_model") self.classifier.train_model(dataframe_1d, model_name="1d_model")
""" """
"""
model_name = "30m_model" model_name = "5m_model"
df = dataframe_30 df = dataframe_5
if self.classifier.model is None: if self.classifier.model is None:
#self.classifier.train_model(df, model_name=model_name, data_file_path=model_name + '_feature_data.csv') #self.classifier.train_model(df, model_name=model_name, data_file_path=model_name + '_feature_data.csv')
self.classifier.load_model(model_name=model_name) self.classifier.load_model(model_name=model_name)
@@ -129,14 +129,14 @@ class ChanLun_SOL_5(IStrategy):
bottom_count = 0 bottom_count = 0
for index in range(int(len(klc_list) * 0.8), len(klc_list)): for index in range(int(len(klc_list) * 0.8), len(klc_list)):
klc = klc_list[index] klc = klc_list[index]
if self.classifier.predict(klc) > 0.4 and (klc.klc_fx_type == Chan_KLC_FX.BOTTOM1 or klc.klc_fx_type == Chan_KLC_FX.BOTTOM2): if self.classifier.predict(klc) > 0.37 and (klc.klc_fx_type == Chan_KLC_FX.BOTTOM1 or klc.klc_fx_type == Chan_KLC_FX.BOTTOM2):
features = klc.get_feature_data() features = klc.get_feature_data()
print(klc.end_time, klc.fx, self.classifier.predict(klc), features['klc_macd'], features['klc_macd_hist'], features['klc_rsi'], features['klc_macd_signal']) print(klc.end_time, klc.fx, self.classifier.predict(klc), features['klc_volume_ratio'], features['klc_macd_hist'], features['klc_rsi'])
bottom_avg += self.classifier.predict(klc) bottom_avg += self.classifier.predict(klc)
bottom_count += 1 bottom_count += 1
if self.classifier.predict(klc) > 0.35 and (klc.klc_fx_type == Chan_KLC_FX.TOP1 or klc.klc_fx_type == Chan_KLC_FX.TOP2): if self.classifier.predict(klc) > 0.37 and (klc.klc_fx_type == Chan_KLC_FX.TOP1 or klc.klc_fx_type == Chan_KLC_FX.TOP2):
features = klc.get_feature_data() features = klc.get_feature_data()
print(klc.end_time, klc.fx, self.classifier.predict(klc), features['klc_macd'], features['klc_macd_hist'], features['klc_rsi'], features['klc_macd_signal']) print(klc.end_time, klc.fx, self.classifier.predict(klc), features['klc_volume_ratio'], features['klc_macd_hist'], features['klc_rsi'])
top_avg += self.classifier.predict(klc) top_avg += self.classifier.predict(klc)
top_count += 1 top_count += 1
if bottom_count > 0: if bottom_count > 0:
@@ -145,7 +145,7 @@ class ChanLun_SOL_5(IStrategy):
top_avg /= top_count top_avg /= top_count
print(bottom_avg, top_avg) print(bottom_avg, top_avg)
print("-------------------------------------------------------------------------------") print("-------------------------------------------------------------------------------")
"""
""" """
self.print_xgb(dataframe, "1m_model") self.print_xgb(dataframe, "1m_model")
self.print_xgb(dataframe_5, "5m_model") self.print_xgb(dataframe_5, "5m_model")
@@ -350,9 +350,9 @@ class ChanLun_SOL_5(IStrategy):
cn3 = 'resample_{}_state'.format(self.get_ticker_indicator()*time) cn3 = 'resample_{}_state'.format(self.get_ticker_indicator()*time)
logger.info(f'{df[cn1][index]}, {df[cn2][index]}, {df[cn3][index]}') logger.info(f'{df[cn1][index]}, {df[cn2][index]}, {df[cn3][index]}')
def add_indicators(self, df): def add_indicators(self, df):
fast = 9 fast = 8
slow = 24 slow = 16
period = 14 period = 6
macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period) macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period)
df['macd'] = macd['macd'] df['macd'] = macd['macd']
df['macdsignal'] = macd['macdsignal'] df['macdsignal'] = macd['macdsignal']
@@ -362,7 +362,17 @@ class ChanLun_SOL_5(IStrategy):
df['ma30'] = ta.EMA(df, timeperiod=30) df['ma30'] = ta.EMA(df, timeperiod=30)
df['ma250'] = ta.MA(df, timeperiod=250) df['ma250'] = ta.MA(df, timeperiod=250)
df['rsi'] = ta.RSI(df, timeperiod=14) df['rsi'] = ta.RSI(df, timeperiod=14)
df['volume_ratio'] = self.cal_volume_ratio(df)
return df return df
def cal_volume_ratio(self, dataframe, window=10):
df = dataframe.copy()
# 计算过去N根K线的平均成交量
df['avg_volume'] = df['volume'].rolling(window=window).mean()
# 计算量比
df['volume_ratio'] = df['volume'] / df['avg_volume']
# 填充缺失值(前N根K线)
df['volume_ratio'] = df['volume_ratio'].fillna(1.0)
return df['volume_ratio']
def local_print(self, df): def local_print(self, df):
fast = 7 fast = 7
slow = 14 slow = 14
+39 -4
View File
@@ -12,7 +12,7 @@ import base64
import time import time
import traceback import traceback
from pytz import timezone from pytz import timezone
import talib.abstract as ta
# 添加父目录到系统路径 # 添加父目录到系统路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
@@ -142,6 +142,7 @@ def get_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time=None):
ret_df.loc[klc_index] = df_copy.loc[index] ret_df.loc[klc_index] = df_copy.loc[index]
klc_index += 1 klc_index += 1
""" """
df = add_indicators(df)
# 如果过滤后没有数据,返回None # 如果过滤后没有数据,返回None
if len(df) == 0: if len(df) == 0:
print("过滤后无数据") print("过滤后无数据")
@@ -154,7 +155,35 @@ def get_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time=None):
print(f"获取数据错误: {e}") print(f"获取数据错误: {e}")
traceback.print_exc() traceback.print_exc()
return None return None
def add_indicators(df):
fast = 8
slow = 16
period = 6
macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period)
df['macd'] = macd['macd']
df['macdsignal'] = macd['macdsignal']
df['macdhist'] = macd['macdhist']
df['ma5'] = (ta.MA(df, timeperiod=5)).fillna(0)
df['ma10'] = (ta.MA(df, timeperiod=10)).fillna(0)
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)
df['macd'] = df['macd'].fillna(0)
df['macdsignal'] = df['macdsignal'].fillna(0)
df['macdhist'] = df['macdhist'].fillna(0)
df['ma5'] = df['ma5'].fillna(0)
df['ma10'] = df['ma10'].fillna(0)
df['ma30'] = df['ma30'].fillna(0)
df['ma250'] = df['ma250'].fillna(0)
df['rsi'] = df['rsi'].fillna(0)
df['avg_volume'] = df['volume'].rolling(10).mean()
# 计算量比
df['volume_ratio'] = df['volume'] / df['avg_volume']
# 填充缺失值(前N根K线)
df['volume_ratio'] = df['volume_ratio'].fillna(1.0)
df['avg_volume'] = df['avg_volume'].fillna(0)
return df
def calculate_macd(df): def calculate_macd(df):
"""计算MACD指标""" """计算MACD指标"""
exp1 = df['close'].ewm(span=12, adjust=False).mean() exp1 = df['close'].ewm(span=12, adjust=False).mean()
@@ -182,7 +211,11 @@ def analyze_chan(df):
zs_list = chan.calculate_zs(bi_list, seg_list) zs_list = chan.calculate_zs(bi_list, seg_list)
# 添加买卖点识别 # 添加买卖点识别
buy_sell_points = identify_trade_points(bi_list, seg_list, zs_list) buy_sell_points = identify_trade_points(bi_list, seg_list, zs_list)
for bi in bi_list:
bi.cal_macdhist()
for bi in bi_list:
bi.cal_macd_div()
#print(bi.start_time, bi.macd_hist, bi.macd_div)
# 提取K线分型信息 # 提取K线分型信息
klc_fx_info = [] klc_fx_info = []
for klc in klc_list: for klc in klc_list:
@@ -411,7 +444,8 @@ def analyze():
'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, '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,
'start_price': bi.start_klc.low if convert_direction(bi.dir) == 1 else bi.start_klc.high, 'start_price': bi.start_klc.low if convert_direction(bi.dir) == 1 else bi.start_klc.high,
'end_price': bi.end_klc.high if convert_direction(bi.dir) == 1 else bi.end_klc.low if bi.end_klc else None, 'end_price': bi.end_klc.high if convert_direction(bi.dir) == 1 else bi.end_klc.low if bi.end_klc else None,
'direction': convert_direction(bi.dir) 'direction': convert_direction(bi.dir),
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
} for bi in analysis_result['bi_list'] if bi.end_klc], } for bi in analysis_result['bi_list'] if bi.end_klc],
'seg_list': [{ 'seg_list': [{
'start_time': seg.start_bi.start_klc.end_time if isinstance(seg.start_bi.start_klc.end_time, str) else seg.start_bi.start_klc.end_time.astimezone(client_tz).isoformat(), 'start_time': seg.start_bi.start_klc.end_time if isinstance(seg.start_bi.start_klc.end_time, str) else seg.start_bi.start_klc.end_time.astimezone(client_tz).isoformat(),
@@ -470,7 +504,8 @@ def analyze():
'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, '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,
'start_price': bi.start_klc.low if convert_direction(bi.dir) == 1 else bi.start_klc.high, 'start_price': bi.start_klc.low if convert_direction(bi.dir) == 1 else bi.start_klc.high,
'end_price': bi.end_klc.high if convert_direction(bi.dir) == 1 else bi.end_klc.low if bi.end_klc else None, 'end_price': bi.end_klc.high if convert_direction(bi.dir) == 1 else bi.end_klc.low if bi.end_klc else None,
'direction': convert_direction(bi.dir) 'direction': convert_direction(bi.dir),
'macd_div': float(bi.macd_div) if hasattr(bi, 'macd_div') else 0
} for bi in element_analysis['bi_list'] if bi.end_klc] } for bi in element_analysis['bi_list'] if bi.end_klc]
# 添加小周期K线数据 # 添加小周期K线数据
+72 -2
View File
@@ -442,6 +442,7 @@
<th>起始价格</th> <th>起始价格</th>
<th>结束价格</th> <th>结束价格</th>
<th>方向</th> <th>方向</th>
<th>MACD背离值</th>
</tr> </tr>
</thead> </thead>
<tbody></tbody> <tbody></tbody>
@@ -1553,6 +1554,39 @@
color: bi.direction === 1 ? '#dc3545' : '#28a745', color: bi.direction === 1 ? '#dc3545' : '#28a745',
lineWidth: 1 lineWidth: 1
}); });
// 在笔的末端添加macd_div值标记
if (bi.macd_div && bi.macd_div !== 0) {
console.log(`添加macd_div标记: ${bi.macd_div.toFixed(2)}, 在时间点: ${endTime}`);
const macdDivLabel = mainChart.addLineSeries({
lastValueVisible: false,
priceLineVisible: false,
});
// 确定标记位置
const markerPosition = bi.direction === 1 ? 'aboveBar' : 'belowBar';
const labelValue = bi.direction === 1 ? endPrice + (endPrice * 0.005) : endPrice - (endPrice * 0.005);
const arrayShape = bi.direction === 1 ? 'arrowDown' : 'arrowUp';
// 简化标记显示
macdDivLabel.setData([
{ time: endTime, value: labelValue }
]);
// 使用不同方式添加文本标记
const textColor = bi.macd_div > 0 ? '#dc3545' : '#28a745';
const textSize = Math.min(14, Math.max(10, Math.abs(bi.macd_div) * 2));
macdDivLabel.setMarkers([
{
time: endTime,
position: markerPosition,
color: textColor,
shape: arrayShape,
text: bi.macd_div.toFixed(2),
}
]);
}
} catch (e) { } catch (e) {
console.error('主周期笔处理出错:', e); console.error('主周期笔处理出错:', e);
} }
@@ -1599,6 +1633,40 @@
color: bi.direction === 1 ? '#9c27b0' : '#673ab7', color: bi.direction === 1 ? '#9c27b0' : '#673ab7',
lineWidth: 1 lineWidth: 1
}); });
// 在笔的末端添加macd_div值标记
if (bi.macd_div && bi.macd_div !== 0) {
console.log(`添加元素周期macd_div标记: ${bi.macd_div.toFixed(2)}, 在时间点: ${endTime}`);
const macdDivLabel = mainChart.addLineSeries({
lastValueVisible: false,
priceLineVisible: false,
});
// 确定标记位置
const markerPosition = bi.direction === 1 ? 'aboveBar' : 'belowBar';
const labelValue = bi.direction === 1 ? endPrice + (endPrice * 0.005) : endPrice - (endPrice * 0.005);
const arrayShape = bi.direction === 1 ? 'arrowDown' : 'arrowUp';
// 简化标记显示
macdDivLabel.setData([
{ time: endTime, value: labelValue }
]);
// 使用不同方式添加文本标记
const textColor = bi.macd_div > 0 ? '#9c27b0' : '#673ab7';
const textSize = Math.min(14, Math.max(10, Math.abs(bi.macd_div) * 2));
macdDivLabel.setMarkers([
{
time: endTime,
position: markerPosition,
color: textColor,
shape: arrayShape,
text: bi.macd_div.toFixed(2),
transparent: true,
}
]);
}
} catch (e) { } catch (e) {
console.error('次周期笔处理出错:', e); console.error('次周期笔处理出错:', e);
} }
@@ -3153,7 +3221,8 @@
{ data: 'end_time', render: formatTime }, { data: 'end_time', render: formatTime },
{ data: 'start_price', render: formatPrice }, { data: 'start_price', render: formatPrice },
{ data: 'end_price', render: formatPrice }, { data: 'end_price', render: formatPrice },
{ data: 'direction', render: formatDirection } { data: 'direction', render: formatDirection },
{ data: 'macd_div', render: formatMacdValue }
] ]
}); });
@@ -3633,7 +3702,8 @@
{ data: 'end_time', render: formatTime }, { data: 'end_time', render: formatTime },
{ data: 'start_price', render: formatPrice }, { data: 'start_price', render: formatPrice },
{ data: 'end_price', render: formatPrice }, { data: 'end_price', render: formatPrice },
{ data: 'direction', render: formatDirection } { data: 'direction', render: formatDirection },
{ data: 'macd_div', render: formatMacdValue }
] ]
}); });