Check 1day data

This commit is contained in:
jackyu66git
2025-06-06 21:42:35 +08:00
parent 6fbdf65422
commit 9ace03b29b
5 changed files with 1951 additions and 1862 deletions
+18 -4
View File
@@ -148,6 +148,20 @@ class ChanKLC():
features[key] = feature_sums[key] / feature_counts[key] features[key] = feature_sums[key] / feature_counts[key]
return features return features
def cal_fx_shape(self):
if self.klc_fx_type != Chan_KLC_FX.UNKNOWN:
if self.pre and self.next and self.next.end_klu:
klc1 = self.pre
klc2 = self
klc3 = self.next
klu_list = []
klu_list.append(klc1.klus)
klu_list.append(klc2.klus)
klu_list.append(klc3.klus)
gap = klc3.end_klu.index - klc1.start_klu.index + 1
if gap < 4:
print(klc1.start_time, klc1.start_klu.index, klc3.end_time, klc3.end_klu.index, gap, self.cal_fx_strength(), self.klc_fx_type)
return gap
def get_feature_data(self): def get_feature_data(self):
features = dict() features = dict()
# 原有基础特征 # 原有基础特征
@@ -1147,7 +1161,7 @@ class ChanKLC():
return features return features
def cal_fx_strength(self): def cal_fx_strength(self, klc_offset=2):
""" """
用self.pre和self.next实现分型强弱判断 用self.pre和self.next实现分型强弱判断
@@ -1172,7 +1186,7 @@ class ChanKLC():
# === 核心判断:分型在笔中的位置 === # === 核心判断:分型在笔中的位置 ===
# 1. 检查这个分型是否能够终结当前笔 # 1. 检查这个分型是否能够终结当前笔
is_bi_end = self._check_if_bi_ending_fx() is_bi_end = self._check_if_bi_ending_fx(klc_offset)
# 2. 检查分型的后续走势确认 # 2. 检查分型的后续走势确认
post_fx_confirmation = self._check_post_fx_confirmation() post_fx_confirmation = self._check_post_fx_confirmation()
@@ -1204,7 +1218,7 @@ class ChanKLC():
# 限制在-3到3范围内 # 限制在-3到3范围内
return max(-3, min(3, base_score)) return max(-3, min(3, base_score))
def _check_if_bi_ending_fx(self): def _check_if_bi_ending_fx(self, klc_offset):
""" """
检查分型是否为笔终结分型 检查分型是否为笔终结分型
返回值: 返回值:
@@ -1221,7 +1235,7 @@ class ChanKLC():
# 获取分型后的几根K线数据 # 获取分型后的几根K线数据
subsequent_klcs = [] subsequent_klcs = []
temp = self.next temp = self.next
for i in range(5): # 检查后续5根K线 for i in range(klc_offset): # 检查后续4根K线
if temp: if temp:
subsequent_klcs.append(temp) subsequent_klcs.append(temp)
temp = temp.next if hasattr(temp, 'next') else None temp = temp.next if hasattr(temp, 'next') else None
+1 -1
View File
@@ -272,7 +272,7 @@ class ChanKLU:
if final_score > 1.8: if final_score > 1.8:
print(self.time, final_score, is_bi_end, post_fx_confirmation, fx_quality) print(self.time, final_score, is_bi_end, post_fx_confirmation, fx_quality)
#print(self.time, final_score, is_bi_end, post_fx_confirmation, fx_quality) #print(self.time, final_score, is_bi_end, post_fx_confirmation, fx_quality)
self.fx_strength = self.cal_fx() #self.fx_strength = self.cal_fx()
return self.fx_strength return self.fx_strength
def _check_if_bi_ending_fx(self): def _check_if_bi_ending_fx(self):
+57 -2
View File
@@ -155,13 +155,64 @@ class ChanLun():
fx_list.append(-1) fx_list.append(-1)
else: else:
fx_list.append(0) fx_list.append(0)
klc_strength_list.append(klc.cal_fx_strength()) klc_strength_list.append(klc.cal_fx_strength(2))
#if klc.klc_fx_type != Chan_KLC_FX.UNKNOWN and klc.cal_fx_strength() > 1: #if klc.klc_fx_type != Chan_KLC_FX.UNKNOWN and klc.cal_fx_strength() > 1:
#print(klc.start_time, klc.end_time, klc.cal_fx_strength(), klc.klc_fx_type, fx_list[-1], klc_strength_list[-1]) #print(klc.start_time, klc.end_time, klc.cal_fx_strength(), klc.klc_fx_type, fx_list[-1], klc_strength_list[-1])
else: else:
klc_strength_list.append(0) klc_strength_list.append(0)
fx_list.append(0) fx_list.append(0)
return klc_strength_list, fx_list return klc_strength_list, fx_list
def get_klc_bsp_list(self, dataframe):
klc_list = self.get_klc_list(dataframe)
bi_list = self.cal_bi_list(klc_list)
bsp_list = []
klc_index = 0
last_top = None
last_bottom = None
for index in range(0, len(dataframe)):
if klc_index == len(klc_list):
klc_index = len(klc_list) - 1
klc = klc_list[klc_index]
if klc.end_klu and klc.end_klu.idx == index:
klc_index += 1
if klc.klc_fx_type == Chan_KLC_FX.TOP1 or klc.klc_fx_type == Chan_KLC_FX.TOP2:
if klc.cal_fx_strength() > 1.0 and klc.cal_fx_shape() < 4:
bsp_list.append(1)
last_top = klc
last_bottom = None
else:
bsp_list.append(0)
elif klc.klc_fx_type == Chan_KLC_FX.BOTTOM1 or klc.klc_fx_type == Chan_KLC_FX.BOTTOM2:
if klc.cal_fx_strength() > 1.0 and klc.cal_fx_shape() < 4:
bsp_list.append(-1)
last_bottom = klc
last_top = None
else:
bsp_list.append(0)
else:
if last_top:
klc_offset = klc.index - last_top.index if klc.index - last_top.index > 2 else 2
last_top_strength = last_top.cal_fx_strength(klc_offset)
if klc.high > last_top.high or (klc_offset > 2 and last_top_strength < 2):
bsp_list.append(-1)
last_top = None
else:
bsp_list.append(0)
elif last_bottom:
klc_offset = klc.index - last_bottom.index if klc.index - last_bottom.index > 2 else 2
last_bottom_strength = last_bottom.cal_fx_strength(klc_offset)
if klc.low < last_bottom.low or (klc_offset > 2 and last_bottom_strength < 2):
bsp_list.append(1)
last_bottom = None
else:
bsp_list.append(0)
else:
bsp_list.append(0)
else:
bsp_list.append(0)
return bsp_list
def get_all_state(self, df_list): def get_all_state(self, df_list):
state_list = [] state_list = []
for df in df_list: for df in df_list:
@@ -231,10 +282,10 @@ class ChanLun():
def get_bi_list(self, dataframe): def get_bi_list(self, dataframe):
bi_list = self.cal_bi_list(self.get_klc_list(dataframe)) bi_list = self.cal_bi_list(self.get_klc_list(dataframe))
return bi_list return bi_list
# --------------------------------------------------------------------
def get_kl_data(self, dataframe:DataFrame): def get_kl_data(self, dataframe:DataFrame):
fields = "time,open,high,low,close,volume" fields = "time,open,high,low,close,volume"
klu_list = [] klu_list = []
last_klu = None
for i in range(0, len(dataframe)): for i in range(0, len(dataframe)):
item = dataframe.iloc[i] item = dataframe.iloc[i]
date = item['date'] date = item['date']
@@ -258,6 +309,10 @@ class ChanLun():
klu = ChanKLU(time_str, o, h, l, c, v) klu = ChanKLU(time_str, o, h, l, c, v)
klu.set_idx(i) klu.set_idx(i)
klu_list.append(klu) klu_list.append(klu)
if last_klu:
last_klu.set_next(klu)
klu.set_pre(last_klu)
last_klu = klu
if 'macd' in item: if 'macd' in item:
klu.set_indicators(item) klu.set_indicators(item)
return klu_list return klu_list
+33 -13
View File
@@ -21,7 +21,8 @@ logger = logging.getLogger(__name__)
# freqtrade plot-dataframe --strategy ChanLun_BTC_15 --datadir user_data/data/binance -c ./user_data/ChanLun_SOL_15.json --timerange=20250309- # freqtrade plot-dataframe --strategy ChanLun_BTC_15 --datadir user_data/data/binance -c ./user_data/ChanLun_SOL_15.json --timerange=20250309-
# freqtrade trade -c ./user_data/Chan/config/ChanLun_BTC_15.json --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies # freqtrade trade -c ./user_data/Chan/config/ChanLun_BTC_15.json --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies
# freqtrade backtesting -c ./user_data/Chan/config/ChanLun_BTC_15.json --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies --timerange=20250525- # freqtrade backtesting --export none -c ./user_data/Chan/config/ChanLun_BTC_15.json --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies --timerange=20250525-
# freqtrade lookahead-analysis --export none -c ./user_data/Chan/config/ChanLun_BTC_15.json --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies --timerange=20250525-
# freqtrade download-data -c ./user_data/Chan/config/ChanLun_BTC_15.json -t 1m --pairs BTC/USDT:USDT --timerange=20250405- # freqtrade download-data -c ./user_data/Chan/config/ChanLun_BTC_15.json -t 1m --pairs BTC/USDT:USDT --timerange=20250405-
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --spaces roi stoploss --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies -c ./user_data/Chan/config/ChanLun_BTC_15.json -e 200 --timerange=20250201-20250401 # freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --spaces roi stoploss --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies -c ./user_data/Chan/config/ChanLun_BTC_15.json -e 200 --timerange=20250201-20250401
@@ -41,12 +42,19 @@ class ChanLun_BTC_15(IStrategy):
"1200": 0 "1200": 0
} }
# 5m and 15m # 5m and 15m
minimal_roi_1 = { minimal_roi = {
"0": 0.1, "0": 0.1,
"60": 0.05, "60": 0.05,
"120": 0.02, "120": 0.02,
"240": 0 "240": 0
} }
# 5m and 15m
minimal_roi_1 = {
"0": 0.05,
"120": 0.02,
"240": 0.01,
"360": 0
}
# 15m and 30m # 15m and 30m
minimal_roi_1 = { minimal_roi_1 = {
"0": 0.1, "0": 0.1,
@@ -61,22 +69,24 @@ class ChanLun_BTC_15(IStrategy):
"3600": 0 "3600": 0
} }
can_short = True can_short = True
lev = 50.0 lev = 1.0
stoploss = -0.3 stoploss = -0.3
bsp_offset = 2
trailing_stop = False trailing_stop = False
trailing_stop_positive = 0.025 trailing_stop_positive = 0.025
trailing_stop_positive_offset = 0.045 trailing_stop_positive_offset = 0.045
trailing_only_offset_is_reached = False trailing_only_offset_is_reached = False
position_adjustment_enable = True position_adjustment_enable = True
startup_candle_count = 600 startup_candle_count = 100
time5 = 5 time5 = 5
time15 = 15 time15 = 15
time30 = 30 time30 = 30
time60 = 60 time60 = 60
time4h = 240 time4h = 240
time5 = 15 time1d = 1440
time5 = 1440
last_time = datetime.now() last_time = datetime.now()
chan = ChanLun() chan = ChanLun()
classifier = ChanLunClassifier(None) classifier = ChanLunClassifier(None)
@@ -108,6 +118,7 @@ class ChanLun_BTC_15(IStrategy):
state_list, fx_list = self.chan.get_klc_strength_list(dataframe_15) state_list, fx_list = self.chan.get_klc_strength_list(dataframe_15)
dataframe_15['state'] = state_list dataframe_15['state'] = state_list
dataframe_15['fx'] = fx_list dataframe_15['fx'] = fx_list
dataframe_15['bsp'] = self.chan.get_klc_bsp_list(dataframe_15)
klc_list = self.chan.get_klc_list(dataframe_15) klc_list = self.chan.get_klc_list(dataframe_15)
bi_list = self.chan.cal_bi_list(klc_list) bi_list = self.chan.cal_bi_list(klc_list)
if self.last_time + timedelta(minutes=1) < datetime.now(): if self.last_time + timedelta(minutes=1) < datetime.now():
@@ -147,6 +158,7 @@ class ChanLun_BTC_15(IStrategy):
# 填充缺失值(前N根K线) # 填充缺失值(前N根K线)
df['volume_ratio'] = df['volume_ratio'].fillna(1.0) df['volume_ratio'] = df['volume_ratio'].fillna(1.0)
return df['volume_ratio'] return df['volume_ratio']
def custom_entry_price(self, pair: str, trade: Trade | None, current_time: datetime, proposed_rate: float, def custom_entry_price(self, pair: str, trade: Trade | None, current_time: datetime, proposed_rate: float,
entry_tag: str | None, side: str, **kwargs) -> float: entry_tag: str | None, side: str, **kwargs) -> float:
new_entryprice = proposed_rate new_entryprice = proposed_rate
@@ -171,11 +183,14 @@ class ChanLun_BTC_15(IStrategy):
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time5) state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time5)
fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time5) fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time5)
bsp_str = 'resample_{}_bsp'.format(self.get_ticker_indicator()*self.time5)
shift = self.time5*self.bsp_offset
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state'] == "-30") #(dataframe['state'] == "-30")
(dataframe[state_str].shift(self.time5) > 1.0) & #(dataframe[state_str].shift(shift) > 1.0) &
(dataframe[fx_str].shift(self.time5) == -1) #(dataframe[fx_str].shift(shift) == -1)
(dataframe[bsp_str].shift(shift) == -1)
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "-10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "-10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10")
@@ -185,8 +200,9 @@ class ChanLun_BTC_15(IStrategy):
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state'] == "-30") #(dataframe['state'] == "-30")
(dataframe[state_str].shift(self.time5) > 1.0) & #(dataframe[state_str].shift(shift) > 1.0) &
(dataframe[fx_str].shift(self.time5) == 1) #(dataframe[fx_str].shift(shift) == 1)
(dataframe[bsp_str].shift(shift) == 1)
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "-10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "-10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10")
@@ -197,11 +213,14 @@ class ChanLun_BTC_15(IStrategy):
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time5) state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time5)
fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time5) fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time5)
bsp_str = 'resample_{}_bsp'.format(self.get_ticker_indicator()*self.time5)
shift = self.time5*self.bsp_offset
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state']== "30") #(dataframe['state']== "30")
(dataframe[state_str].shift(self.time5) > 1.0) & #(dataframe[state_str].shift(shift) > 1.0) &
(dataframe[fx_str].shift(self.time5) == 1) #(dataframe[fx_str].shift(shift) == 1)
(dataframe[bsp_str].shift(shift) == 1)
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10") #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10")
), ),
@@ -209,8 +228,9 @@ class ChanLun_BTC_15(IStrategy):
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state']== "30") #(dataframe['state']== "30")
(dataframe[state_str].shift(self.time5) > 1.0) & #(dataframe[state_str].shift(shift) > 1.0) &
(dataframe[fx_str].shift(self.time5) == -1) #(dataframe[fx_str].shift(shift) == -1)
(dataframe[bsp_str].shift(shift) == -1)
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10") #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10")
), ),
+3 -3
View File
@@ -3250,7 +3250,7 @@
// 构建显示文本,包含分型类型和强度信息 // 构建显示文本,包含分型类型和强度信息
let displayText = `${fx.fx_strength.toFixed(1)}`; let displayText = `${fx.fx_strength.toFixed(1)}`;
if (fx.fx_strength < 1.4) { // 降低阈值让更多分型显示 if (fx.fx_strength < 1.1) { // 降低阈值让更多分型显示
displayText = fx.fx_strength >= 0.8 ? '•' : '' // 0.8以上显示点,0.8以下不显示文本 displayText = fx.fx_strength >= 0.8 ? '•' : '' // 0.8以上显示点,0.8以下不显示文本
} }
@@ -3314,7 +3314,7 @@
// 构建显示文本,包含分型类型和强度信息 // 构建显示文本,包含分型类型和强度信息
let displayText = `${fx.fx_strength.toFixed(1)}`; let displayText = `${fx.fx_strength.toFixed(1)}`;
if (fx.fx_strength < 1.4) { // 降低阈值让更多分型显示 if (fx.fx_strength < 1.3) { // 降低阈值让更多分型显示
displayText = fx.fx_strength >= 0.8 ? '•' : '' // 0.8以上显示点,0.8以下不显示文本 displayText = fx.fx_strength >= 0.8 ? '•' : '' // 0.8以上显示点,0.8以下不显示文本
} }
@@ -3455,7 +3455,7 @@
let strengthColor = fx.is_bottom ? '#9A8C98' : '#F2CC8F'; // 底分型用灰紫色,顶分型用浅黄色 let strengthColor = fx.is_bottom ? '#9A8C98' : '#F2CC8F'; // 底分型用灰紫色,顶分型用浅黄色
let displayText = `${fx.fx_strength.toFixed(1)}`; let displayText = `${fx.fx_strength.toFixed(1)}`;
// 构建小周期分型显示文本 // 构建小周期分型显示文本
if (fx.fx_strength < 1.4){ // 调整小周期阈值 if (fx.fx_strength < 1.3){ // 调整小周期阈值
displayText = fx.fx_strength >= 0.6 ? '•' : '' // 0.6以上显示点 displayText = fx.fx_strength >= 0.6 ? '•' : '' // 0.6以上显示点
} }