diff --git a/ChanEnum.py b/ChanEnum.py index 63d1b98..f5c9a32 100644 --- a/ChanEnum.py +++ b/ChanEnum.py @@ -10,8 +10,12 @@ class Chan_DATA_SRC(Enum): class Chan_ZS_DIR(Enum): UP = auto() DOWN = auto() - +class Chan_K_DIR(Enum): + BULL = auto() + BEAR = auto() + CROSS = auto() class Chan_KL_TYPE(Enum): + K_1S = auto() K_1M = auto() K_DAY = auto() K_WEEK = auto() @@ -21,6 +25,14 @@ class Chan_KL_TYPE(Enum): K_15M = auto() K_30M = auto() K_60M = auto() + K_1H = auto() + K_2H = auto() + K_4H = auto() + K_6H = auto() + K_8H = auto() + K_12H = auto() + K_1D = auto() + K_3D = auto() K_3M = auto() K_QUARTER = auto() diff --git a/ChanKLC.py b/ChanKLC.py index 92aa99a..850fd15 100644 --- a/ChanKLC.py +++ b/ChanKLC.py @@ -1,7 +1,7 @@ import copy from typing import Dict, Optional -from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_KLC_FX +from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_KLC_FX, Chan_K_DIR import ChanKLU import ChanCTime @@ -31,7 +31,15 @@ class ChanKLC(): self.rsi = klu.rsi self.volume_ratio = klu.volume_ratio self.macdhist = 0 - self.strength_list = [] + self.body = klu.body + self.upper_shadow = klu.upper_shadow + self.lower_shadow = klu.lower_shadow + self.body_ratio = klu.body_ratio + self.upper_shadow_ratio = klu.upper_shadow_ratio + self.lower_shadow_ratio = klu.lower_shadow_ratio + self.candle_dir = klu.candle_dir + self.range = klu.range + self.strength = klu.strength 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 @@ -41,6 +49,10 @@ class ChanKLC(): self.end_klu = klu self.end_time = klu.time self.close = klu.close + self.cal_indicators() + self.cal_shape_1() + self.strength = self.cal_klc_strength() + def cal_indicators(self): for index in range(1, len(self.klus)): self.volume += self.klus[index].volume self.rsi += self.klus[index].rsi @@ -50,16 +62,31 @@ 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 cal_shape_1(self): + for index in range(1, len(self.klus)): + self.body += self.klus[index].body + self.upper_shadow += self.klus[index].upper_shadow + self.lower_shadow += self.klus[index].lower_shadow + self.body_ratio += self.klus[index].body_ratio + self.upper_shadow_ratio += self.klus[index].upper_shadow_ratio + self.lower_shadow_ratio += self.klus[index].lower_shadow_ratio + self.range += self.klus[index].range + self.body = self.body / len(self.klus) + self.upper_shadow = self.upper_shadow / len(self.klus) + self.lower_shadow = self.lower_shadow / len(self.klus) + self.body_ratio = self.body_ratio / len(self.klus) + self.upper_shadow_ratio = self.upper_shadow_ratio / len(self.klus) + self.lower_shadow_ratio = self.lower_shadow_ratio / len(self.klus) + self.range = self.range / len(self.klus) + def cal_shape_2(self): + self.body = abs(self.close - self.open) + self.upper_shadow = self.high - max(self.close, self.open) + self.lower_shadow = min(self.close, self.open) - self.low + self.body_ratio = self.body / self.open + self.upper_shadow_ratio = self.upper_shadow / self.open + self.lower_shadow_ratio = self.lower_shadow / self.open + self.candle_dir = Chan_K_DIR.CROSS if self.close == self.open else Chan_K_DIR.BULL if self.close > self.open else Chan_K_DIR.BEAR + self.range = self.high - self.low def set_next(self, klc): self.next = klc def set_pre(self, klc): @@ -1171,10 +1198,20 @@ class ChanKLC(): return features + def cal_klc_strength(self): + strength = 0 + if not self.end_klu: + return strength + if len(self.klus) > 0: + for klu in self.klus: + strength += klu.strength + return strength def cal_fx_strength(self, klc_offset=2): strength = 0 - if self.fx == Chan_FX_TYPE.UNKNOWN or not self.pre or not self.next: + if not self.end_klu: return 0 + if self.fx == Chan_FX_TYPE.UNKNOWN or not self.pre or not self.next: + return strength else: if self.pre and self.next: klc1 = self.pre @@ -1182,34 +1219,27 @@ class ChanKLC(): klc3 = self.next if self.bi: if self.bi.dir == Chan_BI_DIR.UP and self.fx == Chan_FX_TYPE.BOTTOM: - return 0 + return strength if self.bi.dir == Chan_BI_DIR.DOWN and self.fx == Chan_FX_TYPE.TOP: - return 0 + return strength 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: + if self.klc_fx_type == Chan_KLC_FX.BOTTOM1: strength += self.check_bi_end(self.bi) elif self.klc_fx_type == Chan_KLC_FX.BOTTOM2: strength += self.check_bi_end(self.bi) else: - return 0 + return strength return strength def check_bi_end(self, bi): if bi.dir == Chan_BI_DIR.UP: return 1 else: return 1 - 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) - - return def calculate_fx_strength(self): """ 基于专业缠论理论的分型强度评估体系 diff --git a/ChanKLU.py b/ChanKLU.py index 5531dee..8a91bdf 100644 --- a/ChanKLU.py +++ b/ChanKLU.py @@ -1,4 +1,4 @@ -from ChanEnum import Chan_FX_TYPE, Chan_KLU_TYPE +from ChanEnum import Chan_FX_TYPE, Chan_KLU_TYPE, Chan_K_DIR class ChanKLU: def __init__(self, time, open, high, low, close, volume): # _time, _close, _open, _high, _low, _extra_info={} @@ -34,6 +34,28 @@ class ChanKLU: self.fx_confirmed = False # 分型是否确认 self.klu_type = None self.cal_klu_min_max() + self.body = abs(self.close - self.open) + self.upper_shadow = self.high - max(self.close, self.open) + self.lower_shadow = min(self.close, self.open) - self.low + self.body_ratio = self.body / self.open + self.upper_shadow_ratio = self.upper_shadow / self.open + self.lower_shadow_ratio = self.lower_shadow / self.open + self.candle_dir = Chan_K_DIR.CROSS if self.close == self.open else Chan_K_DIR.BULL if self.close > self.open else Chan_K_DIR.BEAR + self.range = self.high - self.low + self.strength = 0 if self.candle_dir == Chan_K_DIR.CROSS else self.cal_klu_strength() + #print(self.open, self.close, self.high, self.low, self.candle_dir, self.strength) + def cal_klu_strength(self): + strength = 0 + if range != 0: + if self.candle_dir == Chan_K_DIR.BULL and (self.upper_shadow + self.lower_shadow) != 0: + strength += self.body / self.range + strength += self.body / (self.upper_shadow + self.lower_shadow) + elif self.candle_dir == Chan_K_DIR.BEAR and (self.upper_shadow + self.lower_shadow) != 0: + strength -=self.body / self.range + strength -= self.body / (self.upper_shadow + self.lower_shadow) + #print(self.time, self.body, self.range, self.upper_shadow, self.lower_shadow, self.candle_dir, strength) + return strength + return strength def cal_klu_min_max(self): """ 计算K线类型:大阳线、大阴线、小阳线、小阴线 diff --git a/ChanLun.py b/ChanLun.py index 6235922..6164a46 100644 --- a/ChanLun.py +++ b/ChanLun.py @@ -312,6 +312,7 @@ class ChanLun(): self.last_peak['low'] = l #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) klu.set_idx(i) klu_list.append(klu) if last_klu: @@ -571,6 +572,13 @@ class ChanLun(): else: last_down_bi = bi down_bi_list.append(bi) + if len(seg_list) > 0: + seg = seg_list[-1] + if seg.end_bi and len(bi_list) > seg.end_bi.index + 1: + bi_index = seg.end_bi.index + for index in range(bi_index+1, len(bi_list)): + bi = bi_list[index] + return seg_list def get_bi_zs_list(self, bi_list): @@ -729,12 +737,37 @@ class ChanLun(): last_bottom = None for klc in klc_list: fx = self.check_fx(klc) + # Do nothing if fx == Chan_FX_TYPE.UNKNOWN: - klc.set_fx(fx) if len(bi_list) > 0: - bi_list[-1].add_klc(klc) - klc.set_bi(bi_list[-1]) + last_bi = bi_list[-1] + #print(klc.start_time, last_bi.start_time, last_bi.end_time, last_bi.dir, last_bi.high, last_bi.low, last_bottom.end_time, "last bi") + if last_top and last_bi.dir == Chan_BI_DIR.DOWN: + if last_bottom and klc.high > last_bi.high: + last_bi.set_end_klc(last_bottom, klc) + bi = ChanBI(last_bottom, len(bi_list), Chan_BI_DIR.UP) + last_bi.set_next(bi) + bi.set_pre(last_bi) + for klc_index in range(last_bi.end_klc.index, len(klc_list)): + bi.add_klc(klc_list[klc_index]) + bi_list.append(bi) + last_top = klc + klc.set_bi(bi) + #print(klc.start_time, bi.start_time, bi.end_time, bi.dir, bi.high, bi.low) + else: + if last_bottom and last_bi.dir == Chan_BI_DIR.UP: + if last_top and klc.low < last_bi.low: + last_bi.set_end_klc(last_top, klc) + bi = ChanBI(last_top, len(bi_list), Chan_BI_DIR.DOWN) + last_bi.set_next(bi) + bi.set_pre(last_bi) + for klc_index in range(last_bi.end_klc.index, len(klc_list)): + bi.add_klc(klc_list[klc_index]) + bi_list.append(bi) + last_bottom = klc + klc.set_bi(bi) + #print(klc.start_time, bi.start_time, bi.end_time, bi.dir, bi.high, bi.low) else: if fx == Chan_FX_TYPE.TOP: if last_top: @@ -754,7 +787,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 +837,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/ChanSEG.py b/ChanSEG.py index 869fa8e..82ae934 100644 --- a/ChanSEG.py +++ b/ChanSEG.py @@ -42,7 +42,7 @@ class ChanSEG(): 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 + self.sure_time = sure_bi.sure_time def pre_set_end_bi(self, bi: ChanBI): self.end_bi = bi if bi: @@ -57,7 +57,7 @@ class ChanSEG(): self.next = seg def set_sure(self, sure_bi): if sure_bi.is_sure: - self.sure_time = sure_bi.end_klc.end_time + self.sure_time = sure_bi.sure_time self.is_sure = True def add_bi(self, bi: ChanBI): if len(self.bi_list) > 1: diff --git a/strategies/ChanLun_BTC_30.py b/strategies/ChanLun_BTC_30.py index a4c3fa2..bb2fbfb 100644 --- a/strategies/ChanLun_BTC_30.py +++ b/strategies/ChanLun_BTC_30.py @@ -237,7 +237,7 @@ class ChanLun_BTC_30(IStrategy): if current_rate < last_low: #print(trade.open_date, last_low, current_rate, "Relay Bottom FX exit") return "Relay Bottom FX exit" - def order_filled(self, pair: str, trade: Trade, order: Order, current_time: datetime, **kwargs) -> None: + def order_filled1(self, pair: str, trade: Trade, order: Order, current_time: datetime, **kwargs) -> None: """ Called right after an order fills. Will be called for all order types (entry, exit, stoploss, position adjustment). diff --git a/web/app.py b/web/app.py index f5a5825..52d4485 100644 --- a/web/app.py +++ b/web/app.py @@ -114,7 +114,7 @@ def get_crypto_kl_data(symbol, timeframe, limit=1000, start_time=None, end_time= batch_size = 1000 else: batch_size = 1500 # 日线及以上可以获取更多 - + batch_size = 1000 # 默认批次大小 # 初始化存储所有K线数据的列表 all_ohlcv = []