diff --git a/.DS_Store b/.DS_Store index 4b9a6fc..8504d65 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/ChanKLC.py b/ChanKLC.py index 9d4b490..d792f13 100644 --- a/ChanKLC.py +++ b/ChanKLC.py @@ -160,7 +160,7 @@ class ChanKLC(): klu_list.append(klc3.klus) gap = klc3.end_klu.index - klc1.start_klu.index + 1 if gap < 4: - pass + pass return gap def get_feature_data(self): features = dict() @@ -1162,269 +1162,44 @@ class ChanKLC(): return features def cal_fx_strength(self, klc_offset=2): - """ - 用self.pre和self.next实现分型强弱判断 - - 核心缠论原理: - - 强分型:出现在笔的末端,能够终结当前笔,标志着趋势转折 - - 弱分型:出现在笔的中间,是中继性质,笔还会继续延伸 - - 返回值: - 3: 极强分型(笔终结+强确认) - 2: 强分型(笔终结) - 1: 偏强分型(可能终结笔) - 0: 中性分型 - -1: 偏弱分型(中继特征明显) - -2: 弱分型(明显中继) - -3: 极弱分型(无效分型) - """ - # 检查是否为分型,且有前后K线数据 - if self.fx == Chan_FX_TYPE.UNKNOWN: + strength = 0 + if self.fx == Chan_FX_TYPE.UNKNOWN or not self.pre or not self.next: return 0 - if not self.pre or not self.next: - return 100 - # === 核心判断:分型在笔中的位置 === - - # 1. 检查这个分型是否能够终结当前笔 - is_bi_end = self._check_if_bi_ending_fx(klc_offset) - - # 2. 检查分型的后续走势确认 - post_fx_confirmation = self._check_post_fx_confirmation() - - # 3. 检查分型的标准性和强度 - fx_quality = self._check_fx_quality() - - # === 综合评分 === - base_score = 0 - - # 笔位置是最重要的判断标准 - if is_bi_end == 2: # 强烈确认笔终结 - base_score = 2 - elif is_bi_end == 1: # 可能笔终结 - base_score = 1 - elif is_bi_end == -1: # 明显中继 - base_score = -2 - elif is_bi_end == -2: # 强烈中继特征 - base_score = -3 - else: # 不确定 - base_score = 0 - - # 后续确认调整 - base_score += post_fx_confirmation - - # 分型质量调整 - base_score += fx_quality - #print(self.start_time, base_score, is_bi_end, post_fx_confirmation, fx_quality) - # 2025-06-07 08:15:00 1.5 0 0.8 0.7 - # 限制在-3到3范围内 - return base_score - - def _check_if_bi_ending_fx(self, klc_offset): - """ - 检查分型是否为笔终结分型 - 返回值: - 2: 强烈确认笔终结 - 1: 可能笔终结 - 0: 不确定 - -1: 明显中继 - -2: 强烈中继特征 - """ - # 检查是否有足够的后续数据来判断 - if not self.next or not hasattr(self.next, 'next'): - return 0 - - # 获取分型后的几根K线数据 - subsequent_klcs = [] - temp = self.next - for i in range(klc_offset): - if temp: - subsequent_klcs.append(temp) - temp = temp.next if hasattr(temp, 'next') else None + else: + if self.pre and self.next: + klc1 = self.pre + klc2 = self + klc3 = self.next + if self.bi: + if self.bi.dir == Chan_BI_DIR.UP and self.fx == Chan_FX_TYPE.BOTTOM: + return 0 + if self.bi.dir == Chan_BI_DIR.DOWN and self.fx == Chan_FX_TYPE.TOP: + return 0 + if self.bi.dir == Chan_BI_DIR.UP: + if self.klc_fx_type == Chan_KLC_FX.TOP1: + strength += self.check_bi_end(self.bi) + elif self.klc_fx_type == Chan_KLC_FX.TOP2: + strength += self.check_bi_end(self.bi) + else: + if self.klc_fx_type == Chan_KLC_FX.BOTTOM1 or self.klc_fx_type == Chan_KLC_FX.BOTTOM2: + strength += self.check_bi_end(self.bi) + elif self.klc_fx_type == Chan_KLC_FX.BOTTOM2: + strength += self.check_bi_end(self.bi) else: - break - - if len(subsequent_klcs) < 2: - return 0 - pass - if self.fx == Chan_FX_TYPE.TOP: - return self._check_top_bi_ending(subsequent_klcs) - else: # BOTTOM - return self._check_bottom_bi_ending(subsequent_klcs) - - def _check_top_bi_ending(self, subsequent_klcs): - """检查顶分型是否为笔终结""" - # 强烈笔终结特征: - # 1. 后续K线持续下跌,且跌破关键位置 - # 2. 没有新的更高的高点出现 - - broken_key_levels = 0 - new_highs = 0 - downward_trend = 0 - - # 检查关键价位突破 - first_low = self.pre.low - middle_low = self.low - key_support = min(first_low, middle_low) - - for i, klc in enumerate(subsequent_klcs): - # 检查是否跌破关键支撑 - if klc.low < key_support: - broken_key_levels += 1 - - # 检查是否出现新高 - if klc.high > self.high: - new_highs += 1 - - # 检查下跌趋势 - if i > 0 and klc.close < subsequent_klcs[i-1].close: - downward_trend += 1 - - # 强烈笔终结:跌破关键位且无新高 - if broken_key_levels >= 1 and new_highs == 0 and downward_trend >= 1: - return 2 - - # 可能笔终结:部分条件满足 - if (broken_key_levels >= 1 and new_highs <= 1) or (new_highs == 0 and downward_trend >= 1): + return 0 + return strength + def check_bi_end(self, bi): + if bi.dir == Chan_BI_DIR.UP: return 1 - - # 明显中继:出现新高且未跌破关键位 - if new_highs >= 2 and broken_key_levels == 0: - return -2 - - # 中继倾向:出现新高 - if new_highs >= 1: - return -1 - - return 0 - - def _check_bottom_bi_ending(self, subsequent_klcs): - """检查底分型是否为笔终结""" - # 强烈笔终结特征: - # 1. 后续K线持续上涨,且突破关键位置 - # 2. 没有新的更低的低点出现 - - broken_key_levels = 0 - new_lows = 0 - upward_trend = 0 - - # 检查关键价位突破 - first_high = self.pre.high - middle_high = self.high - key_resistance = max(first_high, middle_high) - - for i, klc in enumerate(subsequent_klcs): - # 检查是否突破关键阻力 - if klc.high > key_resistance: - broken_key_levels += 1 - - # 检查是否出现新低 - if klc.low < self.low: - new_lows += 1 - - # 检查上涨趋势 - if i > 0 and klc.close > subsequent_klcs[i-1].close: - upward_trend += 1 - - # 强烈笔终结:突破关键位且无新低 - if broken_key_levels >= 1 and new_lows == 0 and upward_trend >= 1: - return 2 - - # 可能笔终结:部分条件满足 - if (broken_key_levels >= 1 and new_lows <= 1) or (new_lows == 0 and upward_trend >= 1): + else: return 1 - - # 明显中继:出现新低且未突破关键位 - if new_lows >= 2 and broken_key_levels == 0: - return -2 - - # 中继倾向:出现新低 - if new_lows >= 1: - return -1 - - return 0 - - def _check_post_fx_confirmation(self): - """ - 检查分型后的走势确认 - 返回值:-1到1的调整分数 - """ - if not self.next: - return 0 - - score = 0 + def cal_klu_strength(self, klc1, klc2, klc3): + klu_list = [] + klu_list.extend(klc1.klus) + klu_list.extend(klc2.klus) + klu_list.extend(klc3.klus) - # 检查第三根K线的确认 - third_klc = self.next - - if self.fx == Chan_FX_TYPE.TOP: - # 顶分型:第三根K线应该走弱 - middle_price = (self.high + self.low) / 2 - - if third_klc.close < middle_price: - score += 0.5 - if third_klc.low < self.pre.low: # 跌破第一根K线低点 - score += 0.5 - if third_klc.close < third_klc.open and abs(third_klc.close - third_klc.open) > abs(self.close - self.open) * 0.5: - score += 0.3 # 明显阴线 - - else: # BOTTOM - # 底分型:第三根K线应该走强 - middle_price = (self.high + self.low) / 2 - - if third_klc.close > middle_price: - score += 0.5 - if third_klc.high > self.pre.high: # 突破第一根K线高点 - score += 0.5 - if third_klc.close > third_klc.open and abs(third_klc.close - third_klc.open) > abs(self.close - self.open) * 0.5: - score += 0.3 # 明显阳线 - - return min(1, max(-1, score)) - - def _check_fx_quality(self): - """ - 检查分型本身的质量 - 返回值:-1到1的调整分数 - """ - score = 0 - - # 检查分型的标准性 - if self.fx == Chan_FX_TYPE.TOP: - # 高点突出程度 - high_diff1 = (self.high - self.pre.high) / self.high if self.high > 0 else 0 - high_diff2 = (self.high - self.next.high) / self.high if self.high > 0 else 0 - min_diff = 33*min(high_diff1, high_diff2) - - if min_diff > 0.03: # 非常突出 - score += 0.5 - elif min_diff > 0.01: # 比较突出 - score += 0.2 - elif min_diff < 0.003: # 不够突出 - score -= 0.5 - - else: # BOTTOM - # 低点突出程度 - low_diff1 = (self.pre.low - self.low) / self.pre.low if self.pre.low > 0 else 0 - low_diff2 = (self.next.low - self.low) / self.next.low if self.next.low > 0 else 0 - min_diff = 33*min(low_diff1, low_diff2) - - if min_diff > 0.03: # 非常突出 - score += 0.5 - elif min_diff > 0.01: # 比较突出 - score += 0.2 - elif min_diff < 0.003: # 不够突出 - score -= 0.5 - - # 检查量价配合 - avg_volume = self._calculate_average_volume(lookback=5) - if avg_volume > 0: - volume_ratio = self.volume / avg_volume - if volume_ratio > 1.5: - score += 0.5 - elif volume_ratio < 0.7: - score -= 0.3 - - return min(1, max(-1, score)) - + return def calculate_fx_strength(self): """ 基于专业缠论理论的分型强度评估体系 diff --git a/ChanLun.py b/ChanLun.py index daabe2f..0f407b0 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.start_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) @@ -772,7 +772,7 @@ class ChanLun(): if last_top.index + 4 < klc.index and len(bi_list) > 1: pre_last_bi = bi_list[-2] last_bi = bi_list[-1] - if pre_last_bi.is_sure and not last_bi.is_sure and pre_last_bi.dir == Chan_BI_DIR.UP: + if pre_last_bi.is_sure and not last_bi.is_sure and pre_last_bi.dir == Chan_BI_DIR.UP and False: pre_last_bi.update_bi(klc) bi_list.remove(last_bi) pre_last_bi.set_next(None) @@ -784,7 +784,7 @@ class ChanLun(): #print(klc.start_time, last_bi.start_klc.start_time, "New TOP Found reset last bi") #klc.set_state("10") #print(klc.start_time, klc.fx, "笔卖点Sell 1") - klc.set_klc_fx_type(Chan_KLC_FX.TOP2) + ###klc.set_klc_fx_type(Chan_KLC_FX.TOP2) # when bi is down but the fx is top bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) else: @@ -804,7 +804,7 @@ class ChanLun(): bi.add_klc(klc) bi_list.append(bi) last_top = klc - #print(klc.start_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) @@ -892,7 +892,7 @@ class ChanLun(): if last_bottom.index + 4 < klc.index and len(bi_list) > 1: pre_last_bi = bi_list[-2] last_bi = bi_list[-1] - if pre_last_bi.is_sure and not last_bi.is_sure and pre_last_bi.dir == Chan_BI_DIR.DOWN: + if pre_last_bi.is_sure and not last_bi.is_sure and pre_last_bi.dir == Chan_BI_DIR.DOWN and False: pre_last_bi.update_bi(klc) bi_list.remove(last_bi) pre_last_bi.set_next(None) @@ -904,7 +904,7 @@ class ChanLun(): #print(klc.start_time, last_bi.start_klc.start_time, "New BOTTOM Found reset last bi") #klc.set_state("-10") #print(klc.start_time, klc.fx, "笔买点Buy 1") - klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM2) + ###klc.set_klc_fx_type(Chan_KLC_FX.BOTTOM2) # when bi is up but the fx is bottom bi_list[-1].add_klc(klc) klc.set_bi(bi_list[-1]) else: diff --git a/ChanPY.py b/ChanPY.py index 65fd94a..c06d9b2 100644 --- a/ChanPY.py +++ b/ChanPY.py @@ -1,7 +1,7 @@ import sys import os -sys.path.append(os.path.abspath("/Users/jack/Documents/GitHub/chan.py")) -#sys.path.append(os.path.abspath("/Users/jack/Project/chan.py")) +#sys.path.append(os.path.abspath("/Users/jack/Documents/GitHub/chan.py")) +sys.path.append(os.path.abspath("/Users/jack/Project/chan.py")) from Chan import CChan from BuySellPoint.BS_Point import CBS_Point from ChanConfig import CChanConfig @@ -51,6 +51,7 @@ class ChanPY(): autype=AUTYPE.QFQ, ) klu_list = [] + bsps = [] chanIn = True #def __init__(self, dataframe): #self.klu_list = self.get_kl_data(dataframe) @@ -266,7 +267,7 @@ class ChanPY(): #print(klu.time, bsps[-1], updown[-1], bi_list[-1].is_sure) self.chanIn = False else: - klu = CKLine_Unit(self.create_item_dict(self.get_last_item_data(dataframe), GetColumnNameFromFieldList(fields)), autofix=True) + klu = self.get_last_klu(dataframe) if self.last_kline.time < klu.time: self.chan.trigger_load({self.k_type: [klu]}) # 喂给CChan新增k线 self.last_kline = klu @@ -318,7 +319,6 @@ class ChanPY(): return bsps def get_bsp_state(self, dataframe:DataFrame): fields = "time,open,high,low,close,volume" - bsps = [] if self.chanIn: kl_data = self.get_kl_data(dataframe) bsp_list = [] @@ -337,66 +337,66 @@ class ChanPY(): #print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, lst[-2].fx, bi_list[-1].dir, bi_list[-1].is_sure,klu.close) if bsp_list_pre_len > len(bsp_list): if abs(last_bsp_value) == 1: - bsps.append(1) + self.bsps.append(1) #print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, 98) else: - bsps.append(99) + self.bsps.append(99) else: if bsp_list_pre_len == len(bsp_list): if klu.idx == last_bsp.klu.idx: if last_bsp.klu.idx - last_bsp_index > 3: last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy) - bsps.append(last_bsp_value) + self.bsps.append(last_bsp_value) else: - bsps.append(0) + self.bsps.append(0) last_bsp_index = last_bsp.klu.idx #if abs(last_bsp_value) == 1 or abs(last_bsp_value) == 2: #print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, "Knonw") else: - bsps.append(0) + self.bsps.append(0) else: if klu.idx == last_bsp.klu.idx: if last_bsp.klu.idx - last_bsp_index > 3: last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy) - bsps.append(last_bsp_value) + self.bsps.append(last_bsp_value) else: - bsps.append(0) + self.bsps.append(0) last_bsp_index = last_bsp.klu.idx #if abs(last_bsp_value) == 1 or abs(last_bsp_value) == 2: #print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, "Knonw") else: - bsps.append(0) + self.bsps.append(0) else: - bsps.append(0) + self.bsps.append(0) bsp_list_pre_len = len(bsp_list) self.chanIn = False else: - klu = CKLine_Unit(self.create_item_dict(self.get_last_item_data(dataframe), GetColumnNameFromFieldList(fields)), autofix=True) + klu = self.get_last_klu(dataframe) if self.last_kline.time < klu.time: self.chan.trigger_load({self.k_type: [klu]}) # 喂给CChan新增k线 self.last_kline = klu bsp_list = self.chan.get_bsp() last_bsp = bsp_list[-1] if last_bsp.klu.idx == klu.idx: - bsps.append(self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy)) + self.bsps.append(self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy)) else: - bsps.append(0) - for index in range(0, len(bsps)): - if not (abs(bsps[index]) == 1 or abs(bsps[index]) == 2): - bsps[index] = 0 + self.bsps.append(0) + for index in range(0, len(self.bsps)): + if not (abs(self.bsps[index]) == 1 or abs(self.bsps[index]) == 2): + self.bsps[index] = 0 else: - if bsps[index] == 2: - bsps[index] = 10 + if self.bsps[index] == 2: + self.bsps[index] = 10 else: - if bsps[index] == -2: - bsps[index] = -10 + if self.bsps[index] == -2: + self.bsps[index] = -10 else: - if bsps[index] == 1: - bsps[index] = 1 + if self.bsps[index] == 1: + self.bsps[index] = 1 else: - if bsps[index] == -1: - bsps[index] = -1 + if self.bsps[index] == -1: + self.bsps[index] = -1 else: - bsps[index] = 0 - return bsps + self.bsps[index] = 0 + return self.bsps diff --git a/strategies/ChanLun_BTC_30.py b/strategies/ChanLun_BTC_30.py index 2e30ea7..6385dec 100644 --- a/strategies/ChanLun_BTC_30.py +++ b/strategies/ChanLun_BTC_30.py @@ -49,7 +49,7 @@ class ChanLun_BTC_30(IStrategy): "240": 0 } # 15m and 30m - minimal_roi = { + minimal_roi_1 = { "0": 0.1, "240": 0.05, "480": 0.03, @@ -61,9 +61,9 @@ class ChanLun_BTC_30(IStrategy): "2400": 0.025, "3600": 0 } - can_short = True - lev = 1.0 - stoploss = -0.3 + can_short = False + lev = 2.0 + stoploss = -0.5 trailing_stop = False trailing_stop_positive = 0.025 trailing_stop_positive_offset = 0.045 @@ -105,13 +105,22 @@ class ChanLun_BTC_30(IStrategy): dataframe_4h = self.add_indicators(dataframe_4h) dataframe_1d = self.add_indicators(dataframe_1d) #self.chan.plot_dual(dataframe_5, dataframe_30) - dataframe_5['chanpy_state'] = self.chanpy.get_bsp_state(dataframe_5) + chanpy_state = self.chanpy.get_bsp_state(dataframe_5) + dataframe_5['chanpy_state'] = chanpy_state 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) + #bi_list_30 = self.chan.get_bi_list(dataframe_30) + #bi_list_60 = self.chan.get_bi_list(dataframe_60) if self.last_time + timedelta(minutes=1) < datetime.now(): - + #self.print_bi(bi_list_1) + #self.print_bi(bi_list_5) + #self.print_bi(bi_list_15) + #self.print_bi(bi_list_30) + #self.print_bi(bi_list_60) print("-------------------------------------------------------------------------------") self.last_time = datetime.now() dataframe = resampled_merge(dataframe, dataframe_5) @@ -120,7 +129,11 @@ class ChanLun_BTC_30(IStrategy): #dataframe = resampled_merge(dataframe, dataframe_60) #dataframe = resampled_merge(dataframe, dataframe_4h) return dataframe - + def print_bi(self, bi_list): + if bi_list and len(bi_list) > 2: + bi1 = bi_list[-1] + bi2 = bi_list[-2] + print(bi1.start_time, bi1.end_time, bi1.dir, bi2.start_time, bi2.end_time, bi2.dir) def add_indicators(self, df): fast = 8 slow = 16 @@ -167,16 +180,26 @@ class ChanLun_BTC_30(IStrategy): return new_exitprice def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, - time_in_force: str, current_time: datetime, entry_tag: str | None, - side: str, **kwargs) -> bool: + time_in_force: str, current_time: datetime, entry_tag: str | None, + side: str, **kwargs) -> bool: if self.last_trade: - if self.last_trade.open_date + timedelta(minutes=30) > current_time: - return False + if self.last_trade.is_short: + if side == 'short': + if self.last_trade.open_date + timedelta(minutes=30) > current_time: + return False + else: + return True + else: + if side == 'long': + if self.last_trade.open_date + timedelta(minutes=30) > current_time: + return True + else: + return False #if self.last_trade: #print(self.last_trade.open_date, current_time, self.last_trade.open_date + timedelta(minutes=self.time5)) return True - def custom_exit(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): #dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) #last_candle = dataframe.iloc[-1].squeeze() @@ -220,8 +243,8 @@ class ChanLun_BTC_30(IStrategy): #last_candle = dataframe.iloc[-1].squeeze() klc_list = self.chan.get_klc_list(resample_to_interval(dataframe, self.get_ticker_indicator() * 30)) bi_list = self.chan.cal_bi_list(klc_list) - last_high = klc_list[-3].high - last_low = klc_list[-3].low + last_high = klc_list[-2].high + last_low = klc_list[-2].low if trade.is_short: if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side): trade.set_custom_data(key="entry_candle_high", value=last_high) @@ -234,15 +257,15 @@ class ChanLun_BTC_30(IStrategy): def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time30) fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time30) - chanpy_state_str = 'resample_{}_chanpy_state'.format(self.get_ticker_indicator()*self.time5) - shift_time = self.time30*2 - strength = 2.2 + #chanpy_state_str = 'resample_{}_chanpy_state'.format(self.get_ticker_indicator()*self.time5) + shift_time = self.time30 + strength = 0.9 dataframe.loc[ ( #(dataframe['state'] == "-30") (dataframe[state_str].shift(shift_time) > strength) & - (dataframe[fx_str].shift(shift_time) == -1) & - (dataframe[chanpy_state_str].shift(shift_time+30) == 1) + (dataframe[fx_str].shift(shift_time) == -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.time30)] == "-10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") @@ -253,8 +276,8 @@ class ChanLun_BTC_30(IStrategy): ( #(dataframe['state'] == "-30") (dataframe[state_str].shift(shift_time) > strength) & - (dataframe[fx_str].shift(shift_time) == 1) & - (dataframe[chanpy_state_str].shift(shift_time+30) == -1) + (dataframe[fx_str].shift(shift_time) == 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.time30)] == "-10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") @@ -265,15 +288,15 @@ class ChanLun_BTC_30(IStrategy): def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time30) fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time30) - chanpy_state_str = 'resample_{}_chanpy_state'.format(self.get_ticker_indicator()*self.time5) - shift_time = self.time30*2 - strength = 2.2 + #chanpy_state_str = 'resample_{}_chanpy_state'.format(self.get_ticker_indicator()*self.time5) + shift_time = self.time30 + strength = 0.9 dataframe.loc[ ( #(dataframe['state']== "30") (dataframe[state_str].shift(shift_time) > strength) & - (dataframe[fx_str].shift(shift_time) == 1) & - (dataframe[chanpy_state_str].shift(shift_time+30) == -1) + (dataframe[fx_str].shift(shift_time) == 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.time60)] == "10") ), @@ -282,8 +305,8 @@ class ChanLun_BTC_30(IStrategy): ( #(dataframe['state']== "30") (dataframe[state_str].shift(shift_time) > strength) & - (dataframe[fx_str].shift(shift_time) == -1) & - (dataframe[chanpy_state_str].shift(shift_time+30) == 1) + (dataframe[fx_str].shift(shift_time) == -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.time60)] == "10") ), diff --git a/web/app.py b/web/app.py index 32a4816..f5a5825 100644 --- a/web/app.py +++ b/web/app.py @@ -299,6 +299,10 @@ def add_indicators(df): # 处理Infinity和-Infinity值 df['volume_ratio'] = df['volume_ratio'].replace([float('inf'), float('-inf')], 1.0) + # 计算ATR (Average True Range) - 14周期 + df['atr'] = ta.ATR(df, timeperiod=14) + df['atr'] = df['atr'].fillna(0) + return df def calculate_macd(df): @@ -568,6 +572,8 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta 'middle': element_current_df['element_bb_middle'].tolist(), 'lower': element_current_df['element_bb_lower'].tolist() }, + # 添加次周期ATR数据 + 'element_atr': element_current_df['atr'].tolist(), 'element_klc_fx_info': [{ 'time': format_time_safely(point['time'], client_tz), 'price': float(point['price']), @@ -644,6 +650,8 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta 'middle': current_df['element_bb_middle'].tolist(), 'lower': current_df['element_bb_lower'].tolist() }, + # 添加ATR数据 + 'atr': current_df['atr'].tolist(), 'klc_fx_info': [{ 'time': format_time_safely(point['time'], client_tz), 'price': float(point['price']), @@ -680,6 +688,7 @@ def generate_replay_data(df, client_tz, symbol=None, element_timeframe=None, sta 'element_macd': {'macd': [], 'signal': [], 'histogram': []}, 'element_bollinger': {'upper': [], 'middle': [], 'lower': []}, 'element_element_bollinger': {'upper': [], 'middle': [], 'lower': []}, + 'element_atr': [], 'element_klc_fx_info': [], 'element_klu_fx_info': [] }) @@ -1116,6 +1125,8 @@ def analyze(): 'middle': df['element_bb_middle'].tolist(), 'lower': df['element_bb_lower'].tolist() }, + # 添加ATR数据 + 'atr': df['atr'].tolist(), # 添加K线分型信息 'klc_fx_info': [{ 'time': format_time_safely(point['time'], client_tz), @@ -1173,6 +1184,9 @@ def analyze(): 'lower': element_df['element_bb_lower'].tolist() } + # 添加小周期ATR数据 + result['element_atr'] = element_df['atr'].tolist() + result['element_bi_list'] = [{ 'start_time': bi.start_klc.end_time if isinstance(bi.start_klc.end_time, str) else bi.start_klc.end_time.astimezone(client_tz).isoformat(), 'end_time': (bi.end_klc.end_time if isinstance(bi.end_klc.end_time, str) else bi.end_klc.end_time.astimezone(client_tz).isoformat()) if bi.end_klc else None, diff --git a/web/templates/index.html b/web/templates/index.html index 9230ee8..2059aee 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -407,6 +407,10 @@ +