修改了很多,明天继续
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user