修改了很多,明天继续

This commit is contained in:
jackyu66git
2025-09-25 02:18:21 +08:00
parent daa8c25c91
commit 68e9c38922
6 changed files with 682 additions and 3612 deletions
+206 -32
View File
@@ -1,6 +1,6 @@
from datetime import timedelta
from pandas import DataFrame
from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_SEG_DIR, Chan_ZS_DIR, Chan_BSP_DIR, Chan_BSP_TYPE, Chan_KLC_FX
from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_SEG_DIR, Chan_ZS_DIR, Chan_BSP_DIR, Chan_BSP_TYPE, Chan_KLC_FX, Chan_PRICE_TREND
from ChanKLU import ChanKLU
from ChanKLC import ChanKLC
from ChanBI import ChanBI
@@ -20,40 +20,213 @@ import numpy as np
from ChanMACD import ChanMACD
class TF_DF():
def __init__(self, timeframe, df, ticker_indicator):
self.timeframe = timeframe
self.dataframe = resample_to_interval(df, ticker_indicator*timeframe)
self.ticker_indicator = ticker_indicator
self.klu_list = []
self.klc_list = []
self.bi_list = []
self.zs_list = []
self.bsp_list = []
self.seg_list = []
self.init_TF_DF()
def init_TF_DF(self):
self.klu_list = self.cal_kl_data(self.dataframe)
self.klc_list = self.cal_klc_list(self.klu_list)
self.bi_list = self.cal_bi_list(self.klc_list)
self.seg_list = self.cal_seg_list(self.bi_list)
self.zs_list = self.cal_zs_list(self.bi_list, self.seg_list)
self.chanmacd = ChanMACD(self.klu_list)
self.klu_list = self.chanmacd.cal_macd_state()
def check_fx(self, klc):
def __init__(self, timeframe, df, ticker_indicator):
self.timeframe = timeframe
self.dataframe = resample_to_interval(df, ticker_indicator*timeframe)
self.dataframe = self.add_indicators(self.dataframe)
self.ticker_indicator = ticker_indicator
self.klu_list = []
self.klc_list = []
self.bi_list = []
self.zs_list = []
self.bsp_list = []
self.seg_list = []
self.init_TF_DF()
def init_TF_DF(self):
self.klu_list = self.cal_kl_data(self.dataframe)
self.klc_list = self.cal_klc_list(self.klu_list)
self.bi_list = self.cal_bi_list(self.klc_list)
self.seg_list = self.cal_seg_list(self.bi_list)
self.zs_list = self.cal_zs_list(self.bi_list, self.seg_list)
self.chanmacd = ChanMACD(self.klu_list)
self.klu_list = self.chanmacd.cal_macd_state()
def add_indicators(self, df):
fast = 12
slow = 26
period = 9
macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period)
bb365 = ta.BBANDS(df, timeperiod=365, nbdevup=3.0, nbdevdn=3.0, matype=0)
bb120 = ta.BBANDS(df, timeperiod=120, nbdevup=3.0, nbdevdn=3.0, matype=0)
bb30 = ta.BBANDS(df, timeperiod=41, nbdevup=2.3, nbdevdn=2.3, matype=0)
bb302 = ta.BBANDS(df, timeperiod=41, nbdevup=2.0, nbdevdn=2.0, matype=0)
bb30 = ta.BBANDS(df, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0)
bb302 = ta.BBANDS(df, timeperiod=20, nbdevup=2.0, nbdevdn=2.0, matype=0)
# 计算布林带中轨(移动平均线)
bb30_middle = ta.SMA(df, timeperiod=90)
# 手动计算布林带 %B 指标 (BBP)
# %B = (Price - Lower Band) / (Upper Band - Lower Band)
bbp365 = (df['close'] - bb365['lowerband']) / (bb365['upperband'] - bb365['lowerband'])
bbp120 = (df['close'] - bb120['lowerband']) / (bb120['upperband'] - bb120['lowerband'])
bbp30 = (df['close'] - bb30['lowerband']) / (bb30['upperband'] - bb30['lowerband'])
bbp302 = (df['close'] - bb302['lowerband']) / (bb302['upperband'] - bb302['lowerband'])
df['atr'] = ta.ATR(df, timeperiod=14)
df['bbup365'] = bb365['upperband']
df['bblow365'] = bb365['lowerband']
df['bbp365'] = bbp365
df['bbup120'] = bb120['upperband']
df['bblow120'] = bb120['lowerband']
df['bbp120'] = bbp120
df['bbup30'] = bb30['upperband']
df['bblow30'] = bb30['lowerband']
df['bbmiddle30'] = bb30_middle # 添加bb30中轨
df['bbp30'] = bbp30
df['bbup302'] = bb302['upperband']
df['bblow302'] = bb302['lowerband']
df['bbp302'] = bbp302
df['macd'] = macd['macd']
df['macdsignal'] = macd['macdsignal']
df['macdhist'] = macd['macdhist']
df['ema5'] = ta.EMA(df, timeperiod=5)
df['ema10'] = ta.EMA(df, timeperiod=10)
df['ema24'] = ta.EMA(df, timeperiod=24)
df['ema26'] = ta.EMA(df, timeperiod=26)
df['ema52'] = ta.EMA(df, timeperiod=52)
df['rsi'] = ta.RSI(df, timeperiod=14)
df['volume_ratio'] = self.cal_volume_ratio(df)
return df
def check_fx(self, klc):
if klc.pre and klc.next:
if klc.high > klc.pre.high and klc.high > klc.next.high:
if klc.macd > 0 and klc.macd > klc.signal and klc.signal > klc.macdhist:
klc.set_fx(Chan_FX_TYPE.TOP)
#print(klc.start_time, klc.end_time,klc.next.start_time, klc.next.end_time,klc.fx, "TOP")
# print(klc.start_time, klc.end_time,klc.next.start_time, klc.next.end_time,klc.fx, "TOP")
return Chan_FX_TYPE.TOP
elif klc.low < klc.pre.low and klc.low < klc.next.low:
if klc.macd < 0 and klc.macd < klc.signal and klc.signal < klc.macdhist:
klc.set_fx(Chan_FX_TYPE.BOTTOM)
#print(klc.start_time, klc.end_time,klc.next.start_time, klc.next.end_time,klc.fx, "BOTTOM")
# print(klc.start_time, klc.end_time,klc.next.start_time, klc.next.end_time,klc.fx, "BOTTOM")
return Chan_FX_TYPE.BOTTOM
return Chan_FX_TYPE.UNKNOWN
def cal_kl_data(self, dataframe:DataFrame):
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 cal_trend(self, klc_list):
"""
基于价格与EMA24/EMA52的位置关系、以及MACD/Signal/Hist的方向,
为每个KLC打上趋势标签:'UP' / 'DOWN' / 'FLAT'
仅设置 klc.trend,不影响其它字段。
"""
if not klc_list:
return klc_list
last_trend = Chan_PRICE_TREND.UNKNOWN
for klc in klc_list:
price = getattr(klc, 'close', None)
ema24 = getattr(klc, 'ema24', None)
ema52 = getattr(klc, 'ema52', None)
macd = getattr(klc, 'macd', 0) if getattr(klc, 'macd', None) is not None else 0
signal = getattr(klc, 'signal', 0) if getattr(klc, 'signal', None) is not None else 0
hist = getattr(klc, 'macdhist', 0) if getattr(klc, 'macdhist', None) is not None else 0
rsi = getattr(klc, 'rsi', None)
trend = Chan_PRICE_TREND.UNKNOWN
try:
# 有效性
price_valid = price is not None and price != 0
ema24_valid = ema24 is not None and ema24 != 0
ema52_valid = ema52 is not None and ema52 != 0
# 多因子投票
score = 0
# 1) 均线结构 + 价位
if ema24_valid and ema52_valid:
score += 1 if ema24 > ema52 else -1
if price_valid and ema24_valid:
score += 1 if price > ema24 else -1
if price_valid and ema52_valid:
score += 1 if price > ema52 else -1
# 2) MACD结构
score += 1 if macd >= signal else -1
if hist != 0:
score += 1 if hist > 0 else -1
# 3) 动量与均线差分斜率
pre = getattr(klc, 'pre', None)
if pre:
pre_close = getattr(pre, 'close', None)
if price_valid and pre_close is not None:
score += 1 if price >= pre_close else -1
pre_ema24 = getattr(pre, 'ema24', None)
pre_ema52 = getattr(pre, 'ema52', None)
if ema24_valid and ema52_valid and pre_ema24 not in (None, 0) and pre_ema52 not in (None, 0):
spread_now = ema24 - ema52
spread_pre = pre_ema24 - pre_ema52
score += 1 if spread_now >= spread_pre else -1
# 4) RSI 辅助
if rsi is not None:
if rsi >= 55:
score += 1
elif rsi <= 45:
score -= 1
# 5) 指标未就绪回退(EMA/MACD缺失时,用动量与RSI辅助,延续趋势)
has_full_ind = ema24_valid and ema52_valid and not (macd == 0 and signal == 0 and hist == 0)
if not has_full_ind:
# 仅根据价动量/RSI做轻量判断,默认延续 last_trend,除非出现强反向
strong_up = False
strong_down = False
pre = getattr(klc, 'pre', None)
if pre:
pre_close = getattr(pre, 'close', None)
if price_valid and pre_close is not None:
strong_up = (price >= pre_close)
strong_down = (price < pre_close)
if rsi is not None:
if rsi >= 60:
strong_up = True
elif rsi <= 40:
strong_down = True
if last_trend == Chan_PRICE_TREND.UP and not strong_down:
trend = Chan_PRICE_TREND.UP
elif last_trend == Chan_PRICE_TREND.DOWN and not strong_up:
trend = Chan_PRICE_TREND.DOWN
else:
trend = Chan_PRICE_TREND.UP if strong_up and not strong_down else (Chan_PRICE_TREND.DOWN if strong_down and not strong_up else Chan_PRICE_TREND.FLAT)
else:
# 6) 震荡过滤(仅当极近EMA52且MACD贴合时判作震荡)
near_flat = False
if price_valid and ema52_valid:
near_ema52 = abs(price - ema52) / abs(ema52) <= 0.0005 # 0.05%
near_macd = abs(macd - signal) <= (abs(price) * 0.00005 if price_valid else 0)
near_flat = near_ema52 and near_macd
# 7) 动态阈值 + 趋势记忆(更强粘滞:趋势中容忍小幅反分)
if near_flat:
trend = Chan_PRICE_TREND.FLAT
else:
if last_trend == Chan_PRICE_TREND.UP:
# 仅当出现明显反向才翻转,否则维持UP
if score <= -2:
trend = Chan_PRICE_TREND.DOWN
else:
trend = Chan_PRICE_TREND.UP
elif last_trend == Chan_PRICE_TREND.DOWN:
if score >= 2:
trend = Chan_PRICE_TREND.UP
else:
trend = Chan_PRICE_TREND.DOWN
else:
# 初始无记忆时,降低进入门槛
if score >= 1:
trend = Chan_PRICE_TREND.UP
elif score <= -1:
trend = Chan_PRICE_TREND.DOWN
else:
trend = Chan_PRICE_TREND.FLAT
except Exception:
trend = Chan_PRICE_TREND.UNKNOWN
# 写回趋势
if hasattr(klc, 'set_trend'):
klc.set_trend(trend)
else:
setattr(klc, 'trend', trend)
last_trend = trend
price_diff = klc.close - klc.pre.close if klc.pre else 0
print(klc.start_time, klc.end_time, klc.close, klc.ema24, klc.ema52, klc.macd, klc.signal, klc.macdhist, klc.trend, price_diff)
#print(klc.start_time, klc.end_time, klc.trend, price_diff)
return klc_list
def cal_kl_data(self, dataframe:DataFrame):
fields = "time,open,high,low,close,volume"
klu_list = []
last_klu = None
@@ -65,8 +238,8 @@ class TF_DF():
l = item['low']
c = item['close']
v = item['volume']
#time_obj = date.fromtimestamp(date)
#date = date + timedelta(hours=8)
# time_obj = date.fromtimestamp(date)
# date = date + timedelta(hours=8)
time_str = date.strftime('%Y-%m-%d %H:%M:%S')
item_data = [
time_str,
@@ -76,9 +249,9 @@ class TF_DF():
c,
v
]
#klu = KLU(self.create_item_dict(item_data, GetColumnNameFromFieldList(fields)))
# klu = KLU(self.create_item_dict(item_data, GetColumnNameFromFieldList(fields)))
klu = ChanKLU(time_str, o, h, l, c, v)
#print(klu.time, klu.open, klu.high, klu.low, klu.close, klu.volume)
# print(klu.time, klu.open, klu.high, klu.low, klu.close, klu.volume)
klu.set_idx(i)
klu_list.append(klu)
if last_klu:
@@ -89,7 +262,7 @@ class TF_DF():
klu.set_indicators(item)
return klu_list
def cal_klc_list(self, klu_list):
def cal_klc_list(self, klu_list):
klc_list = []
last_klu = None
macd = ChanMACD(klu_list)
@@ -117,9 +290,10 @@ class TF_DF():
klc = ChanKLC(klu, 0, ddir)
klc_list.append(klc)
last_klu = klu
klc_list = self.cal_trend(klc_list)
return klc_list
def cal_seg_list(self, bi_list):
def cal_seg_list(self, bi_list):
seg_list = []
up_bi_list = []
down_bi_list = []
@@ -707,7 +881,7 @@ class TF_DF():
#print(bi_list[index].start_time, bi_list[index].start_klc.start_time, bi_list[index].dir)
return bi_list
def get_decimal(self, value):
def get_decimal(self, value):
return Decimal("{:.2f}".format(value))
def cal_zs_list(self, bi_list, seg_list):