添加第二类卖卖点

This commit is contained in:
jackyu66git
2025-06-27 02:39:47 +08:00
parent 1c168c27bd
commit 770655c53f
3 changed files with 73 additions and 56 deletions
+6
View File
@@ -40,6 +40,12 @@ class ChanKLC():
self.candle_dir = klu.candle_dir self.candle_dir = klu.candle_dir
self.range = klu.range self.range = klu.range
self.strength = klu.strength self.strength = klu.strength
self.last_top_klc = None
self.last_bottom_klc = None
def set_last_top_klu(self, last_top_klc):
self.last_top_klc = last_top_klc
def set_last_bottom_klc(self, last_bottom_klc):
self.last_bottom_klc = last_bottom_klc
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'])
self.klc_fx_type = klc_fx_type self.klc_fx_type = klc_fx_type
+13 -28
View File
@@ -92,20 +92,11 @@ 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)
def get_klc_state_list(self, dataframe): def get_klc_state_list(self, dataframe):
klu_list = self.get_klu_list(dataframe)
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)
state_list = [] state_list = []
if len(klc_list) > 0: if len(klc_list) > 0:
klc_index = 0 klc_index = 0
# 添加趋势强度判断
dataframe['trend_strength'] = abs(dataframe['close'].pct_change(20))
# 添加波动率判断
dataframe['volatility'] = dataframe['close'].pct_change().rolling(window=20).std()
# 添加成交量趋势
dataframe['volume_trend'] = dataframe['volume'].rolling(window=20).mean()
for index in range(0, len(dataframe)): for index in range(0, len(dataframe)):
if klc_index == len(klc_list): if klc_index == len(klc_list):
klc_index = len(klc_list) - 1 klc_index = len(klc_list) - 1
@@ -113,27 +104,18 @@ class ChanLun():
if klc.end_klu: if klc.end_klu:
if klc.end_klu.idx == index: if klc.end_klu.idx == index:
klc_index += 1 klc_index += 1
features = klc.get_feature_data() if klc.klc_fx_type == Chan_KLC_FX.TOP3:
if (klc.klc_fx_type == Chan_KLC_FX.TOP1 or klc.klc_fx_type == Chan_KLC_FX.TOP2) and klc.bi.dir == Chan_BI_DIR.UP:
state_list.append("10") state_list.append("10")
#print(klc.start_time, klc.klc_fx_type) print(klc.start_time, klc.end_time, klc.klc_fx_type)
elif (klc.klc_fx_type == Chan_KLC_FX.BOTTOM1 or klc.klc_fx_type == Chan_KLC_FX.BOTTOM2) and klc.bi.dir == Chan_BI_DIR.DOWN: elif klc.klc_fx_type == Chan_KLC_FX.BOTTOM3:
state_list.append("-10") state_list.append("-10")
#print(klc.end_time, klc.klc_fx_type, klc.bi.start_time, klc.bi.dir) print(klc.start_time, klc.end_time, klc.klc_fx_type)
else: else:
state_list.append("00") state_list.append("00")
else: else:
state_list.append("00") state_list.append("00")
else: else:
state_list.append("00") state_list.append("00")
klu = klu_list[index]
if klu.volume_ratio > 4.0:
if klu.close < klu.open:
state_list[-1] = "99"
print(klu.time, klu.volume_ratio, "99")
else:
state_list[-1] = "-99"
print(klu.time, klu.volume_ratio, "-99")
else: else:
for index in range(0, len(dataframe)): for index in range(0, len(dataframe)):
state_list.append("00") state_list.append("00")
@@ -405,7 +387,6 @@ class ChanLun():
up_sbi_list = [] up_sbi_list = []
last_up_sbi = ChanSBI(last_up_bi, len(up_sbi_list), last_up_bi.dir) last_up_sbi = ChanSBI(last_up_bi, len(up_sbi_list), last_up_bi.dir)
up_sbi_list.append(last_up_sbi) up_sbi_list.append(last_up_sbi)
last_seg.add_bi(bi)
#up_sbi_list.append(last_up_sbi) #up_sbi_list.append(last_up_sbi)
#print(last_up_bi.start_time, last_up_sbi.start_bi.start_time, "Reset up sbi list 1") #print(last_up_bi.start_time, last_up_sbi.start_bi.start_time, "Reset up sbi list 1")
#print(bi.start_time, look_for_top, "UP 2") #print(bi.start_time, look_for_top, "UP 2")
@@ -434,7 +415,6 @@ class ChanLun():
up_sbi_list = [] up_sbi_list = []
last_up_sbi = ChanSBI(last_up_bi, len(up_sbi_list), last_up_bi.dir) last_up_sbi = ChanSBI(last_up_bi, len(up_sbi_list), last_up_bi.dir)
up_sbi_list.append(last_up_sbi) up_sbi_list.append(last_up_sbi)
last_seg.add_bi(bi)
#up_sbi_list.append(last_up_sbi) #up_sbi_list.append(last_up_sbi)
#print(last_up_bi.start_time, last_up_sbi.start_bi.start_time, "Reset up sbi list 3") #print(last_up_bi.start_time, last_up_sbi.start_bi.start_time, "Reset up sbi list 3")
last_down_sbi = down_sbi last_down_sbi = down_sbi
@@ -449,8 +429,9 @@ class ChanLun():
down_sbi.set_pre(last_down_sbi) down_sbi.set_pre(last_down_sbi)
down_sbi_list.append(down_sbi) down_sbi_list.append(down_sbi)
last_down_sbi = down_sbi last_down_sbi = down_sbi
last_seg.add_bi(bi)
#print(bi.start_time, look_for_top, "UP 4") #print(bi.start_time, look_for_top, "UP 4")
last_seg.add_bi(bi)
else: else:
last_down_sbi = ChanSBI(bi, len(down_sbi_list), bi.dir) last_down_sbi = ChanSBI(bi, len(down_sbi_list), bi.dir)
down_sbi_list.append(last_down_sbi) down_sbi_list.append(last_down_sbi)
@@ -466,8 +447,9 @@ class ChanLun():
up_sbi.set_pre(last_up_sbi) up_sbi.set_pre(last_up_sbi)
up_sbi_list.append(up_sbi) up_sbi_list.append(up_sbi)
last_up_sbi = up_sbi last_up_sbi = up_sbi
last_seg.add_bi(bi)
#print(bi.start_time, look_for_top, "UP 6") #print(bi.start_time, look_for_top, "UP 6")
last_seg.add_bi(bi)
# Last seg is down # Last seg is down
else: else:
if bi.dir == Chan_BI_DIR.UP: if bi.dir == Chan_BI_DIR.UP:
@@ -499,7 +481,6 @@ class ChanLun():
down_sbi_list = [] down_sbi_list = []
last_down_sbi = ChanSBI(last_down_bi, len(down_sbi_list), last_down_bi.dir) last_down_sbi = ChanSBI(last_down_bi, len(down_sbi_list), last_down_bi.dir)
down_sbi_list.append(last_down_sbi) down_sbi_list.append(last_down_sbi)
last_seg.add_bi(bi)
#down_sbi_list.append(last_down_sbi) #down_sbi_list.append(last_down_sbi)
#print(last_down_bi.start_time, last_down_sbi.start_bi.start_time, "Reset down sbi list 1") #print(last_down_bi.start_time, last_down_sbi.start_bi.start_time, "Reset down sbi list 1")
#print(bi.start_time, look_for_top, "DOWN 2") #print(bi.start_time, look_for_top, "DOWN 2")
@@ -528,7 +509,6 @@ class ChanLun():
down_sbi_list = [] down_sbi_list = []
last_down_sbi = ChanSBI(last_down_bi, len(down_sbi_list), last_down_bi.dir) last_down_sbi = ChanSBI(last_down_bi, len(down_sbi_list), last_down_bi.dir)
down_sbi_list.append(last_down_sbi) down_sbi_list.append(last_down_sbi)
last_seg.add_bi(bi)
#down_sbi_list.append(last_down_sbi) #down_sbi_list.append(last_down_sbi)
#print(last_down_bi.start_time, last_down_sbi.start_bi.start_time, "Reset down sbi list 3") #print(last_down_bi.start_time, last_down_sbi.start_bi.start_time, "Reset down sbi list 3")
last_up_sbi = up_sbi last_up_sbi = up_sbi
@@ -586,6 +566,7 @@ class ChanLun():
else: else:
last_down_bi = bi last_down_bi = bi
down_bi_list.append(bi) down_bi_list.append(bi)
"""
if len(seg_list) > 1: if len(seg_list) > 1:
seg = seg_list[-1] seg = seg_list[-1]
last_seg = seg_list[-2] last_seg = seg_list[-2]
@@ -635,6 +616,7 @@ class ChanLun():
last_seg = seg last_seg = seg
last_seg_bi = bi_list[i] last_seg_bi = bi_list[i]
break break
"""
return seg_list return seg_list
def get_bi_zs_list(self, bi_list): def get_bi_zs_list(self, bi_list):
@@ -837,6 +819,7 @@ class ChanLun():
bi_list[-1].add_klc(klc) bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1]) klc.set_bi(bi_list[-1])
klc.set_klc_fx_type(Chan_KLC_FX.TOP3) klc.set_klc_fx_type(Chan_KLC_FX.TOP3)
klc.set_last_top_klu(last_top)
#print(klc.start_time, klc.fx, "二类卖点Sell 1") #print(klc.start_time, klc.fx, "二类卖点Sell 1")
else: else:
# A new top found # A new top found
@@ -957,6 +940,8 @@ class ChanLun():
bi_list[-1].add_klc(klc) bi_list[-1].add_klc(klc)
klc.set_bi(bi_list[-1]) klc.set_bi(bi_list[-1])
klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM3) klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM3)
klc.set_last_bottom_klc(last_bottom)
#print(last_bottom.start_time, last_bottom.end_time, "--------------------------------1")
#print(klc.start_time, klc.fx, "二类买点Buy 1") #print(klc.start_time, klc.fx, "二类买点Buy 1")
else: else:
# A new bottom found # A new bottom found
+53 -27
View File
@@ -1,6 +1,6 @@
# --- Do not remove these libs --- # --- Do not remove these libs ---
from statistics import median from statistics import median
from freqtrade.strategy import IStrategy from freqtrade.strategy import IStrategy, stoploss_from_absolute
import sys import sys
import os import os
# 添加父目录到系统路径 # 添加父目录到系统路径
@@ -61,9 +61,11 @@ class ChanLun_BTC_30(IStrategy):
"2400": 0.025, "2400": 0.025,
"3600": 0 "3600": 0
} }
can_short = False can_short = True
lev = 2.0 lev = 2.0
stoploss = -0.5 stoploss = -0.5
use_custom_stoploss = True
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
@@ -77,10 +79,12 @@ class ChanLun_BTC_30(IStrategy):
time30 = 30 time30 = 30
time60 = 60 time60 = 60
time4h = 240 time4h = 240
time30 = 60
last_time = datetime.now() last_time = datetime.now()
chan = ChanLun() chan = ChanLun()
chanpy = ChanPY() chanpy = ChanPY()
classifier = ChanLunClassifier(None) classifier = ChanLunClassifier(None)
last_order = None
last_trade = None last_trade = None
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
@@ -107,9 +111,9 @@ class ChanLun_BTC_30(IStrategy):
#self.chan.plot_dual(dataframe_5, dataframe_30) #self.chan.plot_dual(dataframe_5, dataframe_30)
chanpy_state = self.chanpy.get_bsp_state(dataframe_5) chanpy_state = self.chanpy.get_bsp_state(dataframe_5)
dataframe_5['chanpy_state'] = chanpy_state dataframe_5['chanpy_state'] = chanpy_state
state_list, fx_list = self.chan.get_klc_strength_list(dataframe_30) state_list = self.chan.get_klc_state_list(dataframe_60)
dataframe_30['state'] = state_list dataframe_60['state'] = state_list
dataframe_30['fx'] = fx_list dataframe_60['fx'] = state_list
#bi_list_1 = self.chan.get_bi_list(dataframe) #bi_list_1 = self.chan.get_bi_list(dataframe)
#bi_list_5 = self.chan.get_bi_list(dataframe_5) #bi_list_5 = self.chan.get_bi_list(dataframe_5)
@@ -126,7 +130,7 @@ class ChanLun_BTC_30(IStrategy):
print("-------------------------------------------------------------------------------") print("-------------------------------------------------------------------------------")
self.last_time = datetime.now() self.last_time = datetime.now()
dataframe = resampled_merge(dataframe, dataframe_5) dataframe = resampled_merge(dataframe, dataframe_5)
dataframe = resampled_merge(dataframe, dataframe_30) dataframe = resampled_merge(dataframe, dataframe_60)
#dataframe = resampled_merge(dataframe, dataframe_30) #dataframe = resampled_merge(dataframe, dataframe_30)
#dataframe = resampled_merge(dataframe, dataframe_60) #dataframe = resampled_merge(dataframe, dataframe_60)
#dataframe = resampled_merge(dataframe, dataframe_4h) #dataframe = resampled_merge(dataframe, dataframe_4h)
@@ -188,7 +192,7 @@ class ChanLun_BTC_30(IStrategy):
new_exitprice = proposed_rate - 50 new_exitprice = proposed_rate - 50
return new_exitprice return new_exitprice
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, def confirm_trade_entry1(self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time: datetime, entry_tag: str | None, time_in_force: str, current_time: datetime, entry_tag: str | None,
side: str, **kwargs) -> bool: side: str, **kwargs) -> bool:
if self.last_trade: if self.last_trade:
@@ -207,7 +211,20 @@ class ChanLun_BTC_30(IStrategy):
#if self.last_trade: #if self.last_trade:
#print(self.last_trade.open_date, current_time, self.last_trade.open_date + timedelta(minutes=self.time5)) #print(self.last_trade.open_date, current_time, self.last_trade.open_date + timedelta(minutes=self.time5))
return True return True
def custom_stoploss1(self, pair: str, trade: Trade, current_time: datetime,
current_rate: float, current_profit: float, after_fill: bool,
**kwargs) -> float | None:
last_high = trade.get_custom_data(key="entry_candle_high")
last_low = trade.get_custom_data(key="entry_candle_low")
# Convert absolute price to percentage relative to current_rate
if last_high:
return stoploss_from_absolute(last_high, current_rate, is_short=trade.is_short)
if last_low:
return stoploss_from_absolute(last_low, current_rate, is_short=trade.is_short)
# return maximum stoploss value, keeping current stoploss price unchanged
return None
def custom_exit1(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, def custom_exit1(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
current_profit: float, **kwargs): current_profit: float, **kwargs):
#dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) #dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
@@ -229,15 +246,15 @@ class ChanLun_BTC_30(IStrategy):
""" """
if trade.is_short: if trade.is_short:
last_high = trade.get_custom_data(key="entry_candle_high") last_high = trade.get_custom_data(key="entry_candle_high")
if current_rate > last_high: if last_high and current_rate > last_high:
#print(trade.open_date, last_high, current_rate, "Relay Top FX exit") #print(trade.open_date, last_high, current_rate, "Relay Top FX exit")
return "Relay Top FX exit" return "Relay Top FX exit"
else: else:
last_low = trade.get_custom_data(key="entry_candle_low") last_low = trade.get_custom_data(key="entry_candle_low")
if current_rate < last_low: if last_low and current_rate < last_low:
#print(trade.open_date, last_low, current_rate, "Relay Bottom FX exit") #print(trade.open_date, last_low, current_rate, "Relay Bottom FX exit")
return "Relay Bottom FX exit" return "Relay Bottom FX exit"
def order_filled1(self, pair: str, trade: Trade, order: Order, current_time: datetime, **kwargs) -> None: def order_filled(self, pair: str, trade: Trade, order: Order, current_time: datetime, **kwargs) -> None:
""" """
Called right after an order fills. Called right after an order fills.
Will be called for all order types (entry, exit, stoploss, position adjustment). Will be called for all order types (entry, exit, stoploss, position adjustment).
@@ -250,17 +267,26 @@ class ChanLun_BTC_30(IStrategy):
# Obtain pair dataframe (just to show how to access it) # Obtain pair dataframe (just to show how to access it)
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
#last_candle = dataframe.iloc[-1].squeeze() #last_candle = dataframe.iloc[-1].squeeze()
klc_list = self.chan.get_klc_list(resample_to_interval(dataframe, self.get_ticker_indicator() * 30)) klc_list = self.chan.get_klc_list(resample_to_interval(dataframe, self.get_ticker_indicator() * self.time30))
bi_list = self.chan.cal_bi_list(klc_list) bi_list = self.chan.cal_bi_list(klc_list)
last_high = klc_list[-2].high if self.last_order is None:
last_low = klc_list[-2].low if trade.is_short and klc_list[-2].last_top_klc:
if trade.is_short: if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side):
if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side): last_high = klc_list[-2].last_top_klc.high
trade.set_custom_data(key="entry_candle_high", value=last_high) print(klc_list[-2].start_time, "--------------------------------", order.order_date, order.side, last_high)
trade.set_custom_data(key="entry_candle_high", value=last_high)
else:
if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side) and klc_list[-2].last_bottom_klc:
last_low = klc_list[-2].last_bottom_klc.low
trade.set_custom_data(key="entry_candle_low", value=last_low)
print(klc_list[-2].start_time, "--------------------------------", order.order_date, order.side, last_low)
#print(trade.open_date, trade.close_date, last_high, last_low, order.ft_order_side, klc_list[-2].start_time, klc_list[-2].end_time)
self.last_order = order
else: else:
if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side): if self.last_order.side != order.side:
trade.set_custom_data(key="entry_candle_low", value=last_low) self.last_order = None
#print(trade.open_date, trade.close_date, last_high, last_low, order.ft_order_side, klc_list[-2].start_time, klc_list[-2].end_time) trade.set_custom_data(key="entry_candle_high", value=None)
trade.set_custom_data(key="entry_candle_low", value=None)
self.last_trade = trade self.last_trade = trade
return None return None
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
@@ -272,8 +298,8 @@ class ChanLun_BTC_30(IStrategy):
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state'] == "-30") #(dataframe['state'] == "-30")
(dataframe[state_str].shift(shift_time) > strength) & (dataframe[state_str].shift(shift_time) == "-10")
(dataframe[fx_str].shift(shift_time) == -1) #(dataframe[fx_str].shift(shift_time) == -1)
#(dataframe[chanpy_state_str].shift(shift_time+30) == 1) #(dataframe[chanpy_state_str].shift(shift_time+30) == 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") &
@@ -284,8 +310,8 @@ class ChanLun_BTC_30(IStrategy):
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state'] == "-30") #(dataframe['state'] == "-30")
(dataframe[state_str].shift(shift_time) > strength) & (dataframe[state_str].shift(shift_time) == "10")
(dataframe[fx_str].shift(shift_time) == 1) #(dataframe[fx_str].shift(shift_time) == 1)
#(dataframe[chanpy_state_str].shift(shift_time+30) == -1) #(dataframe[chanpy_state_str].shift(shift_time+30) == -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") &
@@ -303,8 +329,8 @@ class ChanLun_BTC_30(IStrategy):
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state']== "30") #(dataframe['state']== "30")
(dataframe[state_str].shift(shift_time) > strength) & (dataframe[state_str].shift(shift_time) == "101")
(dataframe[fx_str].shift(shift_time) == 1) #(dataframe[fx_str].shift(shift_time) == 1)
#(dataframe[chanpy_state_str].shift(shift_time+30) == -1) #(dataframe[chanpy_state_str].shift(shift_time+30) == -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")
@@ -313,8 +339,8 @@ class ChanLun_BTC_30(IStrategy):
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state']== "30") #(dataframe['state']== "30")
(dataframe[state_str].shift(shift_time) > strength) & (dataframe[state_str].shift(shift_time) == "-101")
(dataframe[fx_str].shift(shift_time) == -1) #(dataframe[fx_str].shift(shift_time) == -1)
#(dataframe[chanpy_state_str].shift(shift_time+30) == 1) #(dataframe[chanpy_state_str].shift(shift_time+30) == 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")