From 6e1c335d2837f2b99f76fb64041d19bb6dd0b55c Mon Sep 17 00:00:00 2001 From: jackyu66git Date: Thu, 19 Jun 2025 18:39:02 +0800 Subject: [PATCH] Change some thing --- ChanBI.py | 1 + ChanKLC.py | 12 +++++++- ChanLun.py | 4 +-- ChanPY.py | 2 +- ChanSEG.py | 4 +++ strategies/ChanLun_BTC_30.py | 9 ++++++ strategies/HammerRsiStrategy.py | 53 +++++++++++++++++++++++++++++++++ web/templates/index.html | 10 ++++++- 8 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 strategies/HammerRsiStrategy.py diff --git a/ChanBI.py b/ChanBI.py index f9a0f83..9426bb2 100644 --- a/ChanBI.py +++ b/ChanBI.py @@ -30,6 +30,7 @@ class ChanBI(): self.macd_div = 0.0 else: self.macd_div = self.macd_hist / self.pre.pre.macd_hist + #print(self.start_time, self.end_time, self.macd_hist, self.pre.pre.macd_hist, self.macd_div) def cal_macdhist(self): self.macd_hist = 0 for klc in self.klc_list: diff --git a/ChanKLC.py b/ChanKLC.py index d792f13..92aa99a 100644 --- a/ChanKLC.py +++ b/ChanKLC.py @@ -31,6 +31,7 @@ class ChanKLC(): self.rsi = klu.rsi self.volume_ratio = klu.volume_ratio self.macdhist = 0 + self.strength_list = [] 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']) self.klc_fx_type = klc_fx_type @@ -49,7 +50,16 @@ class ChanKLC(): self.volume_ratio = self.volume_ratio / len(self.klus) self.volume = self.volume / len(self.klus) self.macdhist = self.macdhist / len(self.klus) - + self.cal_self_strength() + def cal_self_strength(self): + strength = 0 + if self.klus: + if len(self.klus) == 1: + strength = 1 + else: + if len(self.klus) > 1: + strength = 0 + self.strength_list.append(strength) def set_next(self, klc): self.next = klc def set_pre(self, klc): diff --git a/ChanLun.py b/ChanLun.py index 0f407b0..6235922 100644 --- a/ChanLun.py +++ b/ChanLun.py @@ -754,7 +754,7 @@ class ChanLun(): last_top = klc #print(klc.start_time, klc.fx, bi_list[-1].dir, "Last Top Change 1") klc.set_klc_fx_type(Chan_KLC_FX.TOP1) - print(klc.end_time, klc.fx, "一类卖点Sell 1") + #print(klc.end_time, klc.fx, "一类卖点Sell 1") #klc.set_fx(fx) #klc.set_state("10") bi_list[-1].add_klc(klc) @@ -804,7 +804,7 @@ class ChanLun(): bi.add_klc(klc) bi_list.append(bi) last_top = klc - print(klc.end_time, klc.fx, bi_list[-1].dir, "Last Top Change 2") + #print(klc.end_time, klc.fx, bi_list[-1].dir, "Last Top Change 2") klc.set_klc_fx_type(Chan_KLC_FX.TOP2) #klc.set_state('30') bi_list[-1].add_klc(klc) diff --git a/ChanPY.py b/ChanPY.py index c06d9b2..0096f3c 100644 --- a/ChanPY.py +++ b/ChanPY.py @@ -36,7 +36,7 @@ class ChanPY(): "divergence_rate": float("inf"), "bsp2_follow_1": False, "bsp3_follow_1": False, - "min_zs_cnt": 0, + "min_zs_cnt": 1, "bs1_peak": False, "macd_algo": "peak", "bs_type": '1,2,3a,1p,2s,3b', diff --git a/ChanSEG.py b/ChanSEG.py index 0eb1174..869fa8e 100644 --- a/ChanSEG.py +++ b/ChanSEG.py @@ -8,6 +8,8 @@ from ChanBI import ChanBI class ChanSEG(): def __init__(self, start_bi: ChanBI, index, ddir=Chan_SEG_DIR.UP): self.start_bi = start_bi + self.start_time = start_bi.start_time + self.end_time = None self.end_bi = None self.dir = ddir self.low = 0 @@ -38,6 +40,7 @@ class ChanSEG(): else: self.low = bi.low self.is_sure = True + self.end_time = bi.end_klc.end_time if sure_bi.is_sure: self.sure_time = sure_bi.end_klc.end_time def pre_set_end_bi(self, bi: ChanBI): @@ -47,6 +50,7 @@ class ChanSEG(): self.high = bi.high else: self.low = bi.low + self.end_time = bi.end_klc.end_time def set_pre(self, seg): self.pre = seg def set_next(self, seg): diff --git a/strategies/ChanLun_BTC_30.py b/strategies/ChanLun_BTC_30.py index 6385dec..a4c3fa2 100644 --- a/strategies/ChanLun_BTC_30.py +++ b/strategies/ChanLun_BTC_30.py @@ -110,6 +110,7 @@ class ChanLun_BTC_30(IStrategy): state_list, fx_list = self.chan.get_klc_strength_list(dataframe_30) dataframe_30['state'] = state_list dataframe_30['fx'] = fx_list + #bi_list_1 = self.chan.get_bi_list(dataframe) #bi_list_5 = self.chan.get_bi_list(dataframe_5) #bi_list_15 = self.chan.get_bi_list(dataframe_15) @@ -121,6 +122,7 @@ class ChanLun_BTC_30(IStrategy): #self.print_bi(bi_list_15) #self.print_bi(bi_list_30) #self.print_bi(bi_list_60) + self.print_seg(dataframe_5) print("-------------------------------------------------------------------------------") self.last_time = datetime.now() dataframe = resampled_merge(dataframe, dataframe_5) @@ -129,6 +131,13 @@ class ChanLun_BTC_30(IStrategy): #dataframe = resampled_merge(dataframe, dataframe_60) #dataframe = resampled_merge(dataframe, dataframe_4h) return dataframe + def print_seg(self, dataframe): + klc_list = self.chan.get_klc_list(dataframe) + bi_list = self.chan.cal_bi_list(klc_list) + seg_list = self.chan.get_seg_list(bi_list) + seg = seg_list[-1] + bi = bi_list[-1] + print(seg.start_time, seg.dir, bi.start_time, bi.dir) def print_bi(self, bi_list): if bi_list and len(bi_list) > 2: bi1 = bi_list[-1] diff --git a/strategies/HammerRsiStrategy.py b/strategies/HammerRsiStrategy.py new file mode 100644 index 0000000..c82cdb3 --- /dev/null +++ b/strategies/HammerRsiStrategy.py @@ -0,0 +1,53 @@ +from freqtrade.strategy import IStrategy +from pandas_ta import ema +import pandas as pd +import pandas_ta as ta +import numpy as np +from datetime import datetime, timedelta +from freqtrade.persistence import Trade, Order +# freqtrade backtesting -c ./user_data/Chan/config/ChanLun_BTC_30.json --strategy HammerRsiStrategy --strategy-path ./user_data/Chan/strategies --timerange=20250520- + + +class HammerRsiStrategy(IStrategy): + timeframe = "1m" # 1分钟K线 + minimal_roi = {"0": 0.005} # 0.5% 止盈 + stoploss = -0.002 # 0.2% 固定止损 + trailing_stop = True + trailing_stop_positive = 0.001 # 0.1% 追踪止损 + trailing_stop_positive_offset = 0.002 # 0.2% 触发追踪止损 + startup_candle_count = 20 # 启动K线数 + + def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: + dataframe['rsi'] = ta.rsi(dataframe['close'], length=14) + dataframe['ema_fast'] = ta.ema(dataframe['close'], length=5) + dataframe['ema_slow'] = ta.ema(dataframe['close'], length=20) + dataframe['atr'] = ta.atr(dataframe['high'], dataframe['low'], dataframe['close'], length=14) + return dataframe + + def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: + conditions = ( + (dataframe['ema_fast'] > dataframe['ema_slow']) & # 快EMA上穿慢EMA + (dataframe['rsi'] < 45) # RSI < 45 + ) + print(f"Signal check: ema_fast={dataframe['ema_fast'].iloc[-1]}, ema_slow={dataframe['ema_slow'].iloc[-1]}, rsi={dataframe['rsi'].iloc[-1]}") + dataframe.loc[conditions, ['enter_long', 'enter_tag']] = (1, 'ema_rsi_entry') + return dataframe + + def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: + conditions = ( + (dataframe['ema_fast'] < dataframe['ema_slow']) | # 快EMA下穿慢EMA + (dataframe['rsi'] > 60) # RSI > 60 + ) + dataframe.loc[conditions, ['exit_long', 'exit_tag']] = (1, 'ema_rsi_exit') + return dataframe + + def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + atr = dataframe['atr'].iloc[-1] + return -1.5 * atr / current_rate # 止损为1.5倍ATR + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + entry_tag: str) -> float: + return proposed_stake * 0.01 # 1%账户余额 \ No newline at end of file diff --git a/web/templates/index.html b/web/templates/index.html index 2059aee..faf8c10 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -1124,6 +1124,9 @@ // 应用保存的逻辑范围到所有图表 tvWidget.mainChart.timeScale().setVisibleLogicalRange(logicalRange); tvWidget.volumeChart.timeScale().setVisibleLogicalRange(logicalRange); + if (tvWidget.atrChart) { + tvWidget.atrChart.timeScale().setVisibleLogicalRange(logicalRange); + } if (tvWidget.macdChart) { tvWidget.macdChart.timeScale().setVisibleLogicalRange(logicalRange); } @@ -1131,6 +1134,9 @@ // 如果没有逻辑范围,使用时间戳范围 tvWidget.mainChart.timeScale().setVisibleRange(visibleRange); tvWidget.volumeChart.timeScale().setVisibleRange(visibleRange); + if (tvWidget.atrChart) { + tvWidget.atrChart.timeScale().setVisibleRange(visibleRange); + } if (tvWidget.macdChart) { tvWidget.macdChart.timeScale().setVisibleRange(visibleRange); } @@ -5355,14 +5361,16 @@ if (logicalRange) { tvWidget.mainChart.timeScale().setVisibleLogicalRange(logicalRange); if (tvWidget.volumeChart) tvWidget.volumeChart.timeScale().setVisibleLogicalRange(logicalRange); + if (tvWidget.atrChart) tvWidget.atrChart.timeScale().setVisibleLogicalRange(logicalRange); if (tvWidget.macdChart) tvWidget.macdChart.timeScale().setVisibleLogicalRange(logicalRange); } else if (visibleRange) { tvWidget.mainChart.timeScale().setVisibleRange(visibleRange); if (tvWidget.volumeChart) tvWidget.volumeChart.timeScale().setVisibleRange(visibleRange); + if (tvWidget.atrChart) tvWidget.atrChart.timeScale().setVisibleRange(visibleRange); if (tvWidget.macdChart) tvWidget.macdChart.timeScale().setVisibleRange(visibleRange); } - console.log('图表可见范围已恢复'); + console.log('图表可见范围已恢复(包括ATR图表)'); } else { console.error('恢复图表可见范围失败 - 图表未初始化'); }