Files
Chan/ChanKLC.py
T
2025-11-16 20:58:03 +08:00

216 lines
7.8 KiB
Python

import copy
from typing import Dict, Optional
from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_KLC_FX, Chan_K_DIR, Chan_MACD_STATE, Chan_PRICE_TREND
import ChanKLU
import ChanCTime
# 根据结合律合并K线后的K线
class ChanKLC():
def __init__(self, klu: ChanKLU, index, ddir=Chan_KLINE_DIR.UP):
self.start_time = klu.time
self.end_time = None
self.high = klu.high
self.low = klu.low
self.dir = ddir
self.index = index
self.klu_list = []
self.add_klu(klu)
self.fx = Chan_FX_TYPE.UNKNOWN
self.next = None
self.pre = None
self.start_klu = klu
self.end_klu = None
self.state = "00"
self.open = klu.open
self.close = klu.close
self.volume = klu.volume
self.bi = None
self.distance = 0
self.klc_fx_type = Chan_KLC_FX.UNKNOWN
self.rsi = klu.rsi
self.volume_ratio = klu.volume_ratio
self.macdhist = klu.macdhist
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.bb_out = True
self.macd = 0
self.signal = 0
self.state = Chan_MACD_STATE.UNKNOWN
self.continue_div = False
self.separate_div = False
self.ema52 = klu.ema52
self.ema24 = klu.ema24
self.trend = Chan_PRICE_TREND.UNKNOWN
self.exception = klu.exception
self.klc_dir = Chan_KLINE_DIR.UP if klu.close > klu.open else Chan_KLINE_DIR.DOWN
def set_trend(self, trend):
self.trend = trend
def to_string(self):
out = ""
start = self.start_time if self.start_time is not None else ""
end = self.end_time if self.end_time is not None else ""
price_diff = getattr(self, 'price_diff', None)
out += str(start) + " " + str(end) + " " + str(self.close) + " " + str(self.ema24) + " " + str(self.ema52) + " " + str(self.trend) + " " + str(self.close - self.ema52)
return out
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
#self.cal_fx()
self.cal_bb_out()
def add_klu(self, klu):
self.klu_list.append(klu)
def set_end_klu(self, klu):
self.end_klu = klu
self.end_time = klu.time
self.close = klu.close
for klu in self.klu_list:
if klu.separate_div > 0:
self.separate_div = True
if klu.continue_div:
self.continue_div = klu.continue_div
if klu.macd_state != Chan_MACD_STATE.UNKNOWN:
self.state = klu.macd_state
klu.set_klc(self)
self.klc_dir = Chan_KLINE_DIR.UP if self.close > self.open else Chan_KLINE_DIR.DOWN
self.cal_indicators()
def cal_fx(self):
if self.klc_fx_type == Chan_KLC_FX.TOP1 or self.klc_fx_type == Chan_KLC_FX.TOP2:
#print(self.end_time, self.fx, self.macd, self.macdhist, len(self.klu_list))
if self.state == Chan_MACD_STATE.HIGH_EMPTY and self.macd > 0:
#print(self.end_time, self.state, self.macd, self.klc_fx_type)
self.klc_fx_type = Chan_KLC_FX.TOP6
if self.separate_div or self.continue_div:
self.klc_fx_type = Chan_KLC_FX.TOP7
if self.signal > 0 and self.macd > self.signal:
self.klc_fx_type = Chan_KLC_FX.TOP8
else:
if self.klc_fx_type == Chan_KLC_FX.BOTTOM1 or self.klc_fx_type == Chan_KLC_FX.BOTTOM2:
if self.macdhist > 0 and self.macd < 0:
self.klc_fx_type = Chan_KLC_FX.BOTTOM5
return
if self.state == Chan_MACD_STATE.HIGH_EMPTY and self.macd < 0:
self.klc_fx_type = Chan_KLC_FX.BOTTOM6
#print(self.end_time, self.state, self.macd, self.klc_fx_type)
if self.separate_div or self.continue_div:
self.klc_fx_type = Chan_KLC_FX.BOTTOM7
if self.signal < 0 and self.macd < self.signal:
self.klc_fx_type = Chan_KLC_FX.BOTTOM8
def cal_bb_out(self):
for klu in self.klu_list:
if self.klc_fx_type == Chan_KLC_FX.TOP1 or self.klc_fx_type == Chan_KLC_FX.TOP2:
#print(self.start_time, self.klc_fx_type, klu.high, klu.bb52upper, self.macd, self.next.macd, klu.time)
if self.high >= klu.bb52upper and klu.bb52upper > 0 and self.next and self.high > self.next.high:
self.klc_fx_type = Chan_KLC_FX.TOP4
print(self.end_time, self.klc_fx_type)
if self.klc_fx_type == Chan_KLC_FX.BOTTOM1 or self.klc_fx_type == Chan_KLC_FX.BOTTOM2:
#print(self.start_time, self.klc_fx_type, klu.low, klu.bb52lower, self.macd, self.next.macd, klu.time)
if self.low <= klu.bb52lower and klu.bb52lower > 0 and self.next and self.low < self.next.low:
self.klc_fx_type = Chan_KLC_FX.BOTTOM4
print(self.end_time, self.klc_fx_type)
def cal_indicators(self):
for index in range(1, len(self.klu_list)):
self.volume += self.klu_list[index].volume
self.rsi += self.klu_list[index].rsi
self.volume_ratio += self.klu_list[index].volume_ratio
self.macdhist += self.klu_list[index].macdhist
self.ema52 += self.klu_list[index].ema52
self.ema24 += self.klu_list[index].ema24
self.rsi = self.rsi / len(self.klu_list)
self.volume_ratio = self.volume_ratio / len(self.klu_list)
self.volume = self.volume / len(self.klu_list)
self.macdhist = self.macdhist / len(self.klu_list)
self.ema52 = self.ema52 / len(self.klu_list)
self.ema24 = self.ema24 / len(self.klu_list)
if len(self.klu_list) > 0:
self.macd = self.klu_list[-1].macd
self.signal = self.klu_list[-1].signal
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):
self.pre = klc
def set_state(self, state):
self.state = state
def check_klu_included(self, klu):
if self.high >= klu.high-10:
# high大于,low小于,左包含
if self.low <= klu.low+10:
self.add_klu(klu=klu)
# gn>gn-1
if self.dir == Chan_KLINE_DIR.UP:
# UP -> max(dn)
self.low = klu.low
else:
# DOWN -> min(gn)
self.high = klu.high
#self.print(klu, "Z")
return True
# high大于,low大于,不包含
else:
# if self.low > klu.low
# high相等,右包含
if self.high == klu.high:
self.add_klu(klu=klu)
# UP -> max(gn)
if self.dir == Chan_KLINE_DIR.UP:
self.high = klu.high
else:
# DOWN -> min(dn)
self.low = klu.low
return True
else:
return False
else:
# high小于,low大于,右包含
if self.low >= klu.low-10:
self.add_klu(klu=klu)
# gn>gn-1
if self.dir == Chan_KLINE_DIR.UP:
# UP -> max(gn)
self.high = klu.high
else:
# DOWN -> min(dn)
self.low = klu.low
#self.print(klu, "Y")
return True
else:
# high小于,low小于,不包含
return False
def set_fx(self, fx: Chan_FX_TYPE):
self.fx = fx
def cal_invisible(self):
if self.fx == Chan_FX_TYPE.TOP:
if self.macdhist < 0 and self.macd > 0:
self.klc_fx_type = Chan_KLC_FX.TOP5
else:
if self.fx == Chan_FX_TYPE.BOTTOM:
if self.macdhist > 0 and self.macd < 0:
self.klc_fx_type = Chan_KLC_FX.BOTTOM5
def set_pre_fx(self):
if self.pre and self.pre.pre:
self.pre.fx = self.check_fx(self.pre.pre, self.pre)
def check_fx(self, k1, k2):
if k2.high > k1.high and k2.high > self.high:
return Chan_FX_TYPE.TOP
elif k2.low < k1.low and k2.low < self.low:
return Chan_FX_TYPE.BOTTOM
else:
return Chan_FX_TYPE.UNKNOWN
def set_bi(self, bi):
self.bi = bi
self.distance = self.index - bi.start_klc.index
#print(self.start_time, self.distance, bi.index, bi.dir)