Add files to chanlun_1
This commit is contained in:
+238
@@ -0,0 +1,238 @@
|
||||
"""
|
||||
K线包含关系处理模块
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from typing import List, Tuple, Optional
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class KLineElement:
|
||||
"""单个K线元素类"""
|
||||
|
||||
def __init__(self, high: float, low: float, open_price: float,
|
||||
close: float, volume: float, timestamp: pd.Timestamp):
|
||||
"""
|
||||
初始化K线元素
|
||||
|
||||
Args:
|
||||
high: 最高价
|
||||
low: 最低价
|
||||
open_price: 开盘价
|
||||
close: 收盘价
|
||||
volume: 成交量
|
||||
timestamp: 时间戳
|
||||
"""
|
||||
self.high = high
|
||||
self.low = low
|
||||
self.open = open_price
|
||||
self.close = close
|
||||
self.volume = volume
|
||||
self.timestamp = timestamp
|
||||
self.direction = 1 if close >= open_price else -1
|
||||
|
||||
def __repr__(self):
|
||||
return f"KLineElement(H:{self.high}, L:{self.low}, O:{self.open}, C:{self.close})"
|
||||
|
||||
|
||||
class KLine:
|
||||
"""K线包含关系处理类"""
|
||||
|
||||
def __init__(self, data: pd.DataFrame):
|
||||
"""
|
||||
初始化K线处理器
|
||||
|
||||
Args:
|
||||
data: 包含OHLCV数据的DataFrame
|
||||
"""
|
||||
self.original_data = data.copy()
|
||||
self.processed_data = None
|
||||
self.kline_elements = []
|
||||
self._process_data()
|
||||
|
||||
def _process_data(self):
|
||||
"""处理原始数据为K线元素"""
|
||||
self.kline_elements = []
|
||||
|
||||
for idx, row in self.original_data.iterrows():
|
||||
element = KLineElement(
|
||||
high=row['high'],
|
||||
low=row['low'],
|
||||
open_price=row['open'],
|
||||
close=row['close'],
|
||||
volume=row['volume'],
|
||||
timestamp=idx
|
||||
)
|
||||
self.kline_elements.append(element)
|
||||
|
||||
def has_containment(self, k1: KLineElement, k2: KLineElement) -> bool:
|
||||
"""
|
||||
判断两根K线是否存在包含关系
|
||||
|
||||
Args:
|
||||
k1: 第一根K线
|
||||
k2: 第二根K线
|
||||
|
||||
Returns:
|
||||
是否存在包含关系
|
||||
"""
|
||||
# K1包含K2:K1的高低点完全包含K2
|
||||
k1_contains_k2 = (k1.high >= k2.high and k1.low <= k2.low)
|
||||
|
||||
# K2包含K1:K2的高低点完全包含K1
|
||||
k2_contains_k1 = (k2.high >= k1.high and k2.low <= k1.low)
|
||||
|
||||
return k1_contains_k2 or k2_contains_k1
|
||||
|
||||
def merge_contained_klines(self, k1: KLineElement, k2: KLineElement,
|
||||
direction: int) -> KLineElement:
|
||||
"""
|
||||
合并包含关系的K线
|
||||
|
||||
Args:
|
||||
k1: 第一根K线
|
||||
k2: 第二根K线
|
||||
direction: 当前趋势方向(1为上升,-1为下降)
|
||||
|
||||
Returns:
|
||||
合并后的K线
|
||||
"""
|
||||
if direction > 0: # 上升趋势中
|
||||
# 取两根K线的最高点的最大值,最低点的最大值
|
||||
merged_high = max(k1.high, k2.high)
|
||||
merged_low = max(k1.low, k2.low)
|
||||
else: # 下降趋势中
|
||||
# 取两根K线的最高点的最小值,最低点的最小值
|
||||
merged_high = min(k1.high, k2.high)
|
||||
merged_low = min(k1.low, k2.low)
|
||||
|
||||
# 开盘价和收盘价使用第一根K线的值
|
||||
merged_open = k1.open
|
||||
merged_close = k2.close
|
||||
merged_volume = k1.volume + k2.volume
|
||||
merged_timestamp = k2.timestamp # 使用最后一根K线的时间
|
||||
|
||||
return KLineElement(
|
||||
high=merged_high,
|
||||
low=merged_low,
|
||||
open_price=merged_open,
|
||||
close=merged_close,
|
||||
volume=merged_volume,
|
||||
timestamp=merged_timestamp
|
||||
)
|
||||
|
||||
def handle_containment(self) -> List[KLineElement]:
|
||||
"""
|
||||
处理所有K线的包含关系
|
||||
|
||||
Returns:
|
||||
处理包含关系后的K线列表
|
||||
"""
|
||||
if len(self.kline_elements) < 2:
|
||||
return self.kline_elements.copy()
|
||||
|
||||
processed_klines = [self.kline_elements[0]] # 第一根K线
|
||||
|
||||
# 初始方向:根据前两根K线确定
|
||||
if len(self.kline_elements) >= 2:
|
||||
k1, k2 = self.kline_elements[0], self.kline_elements[1]
|
||||
if k2.high > k1.high:
|
||||
current_direction = 1 # 上升
|
||||
elif k2.high < k1.high:
|
||||
current_direction = -1 # 下降
|
||||
else:
|
||||
current_direction = 1 if k2.low >= k1.low else -1
|
||||
else:
|
||||
current_direction = 1
|
||||
|
||||
i = 1
|
||||
while i < len(self.kline_elements):
|
||||
current_k = self.kline_elements[i]
|
||||
last_processed = processed_klines[-1]
|
||||
|
||||
if self.has_containment(last_processed, current_k):
|
||||
# 存在包含关系,进行合并
|
||||
merged = self.merge_contained_klines(
|
||||
last_processed, current_k, current_direction
|
||||
)
|
||||
processed_klines[-1] = merged # 替换最后一个
|
||||
else:
|
||||
# 不存在包含关系,直接添加
|
||||
processed_klines.append(current_k)
|
||||
|
||||
# 更新方向
|
||||
if current_k.high > last_processed.high:
|
||||
current_direction = 1
|
||||
elif current_k.high < last_processed.high:
|
||||
current_direction = -1
|
||||
# 如果high相等,保持原方向
|
||||
|
||||
i += 1
|
||||
|
||||
logger.info(f"包含关系处理完成:{len(self.kline_elements)} -> {len(processed_klines)}")
|
||||
return processed_klines
|
||||
|
||||
def to_dataframe(self, processed_klines: Optional[List[KLineElement]] = None) -> pd.DataFrame:
|
||||
"""
|
||||
将处理后的K线转换为DataFrame
|
||||
|
||||
Args:
|
||||
processed_klines: 处理后的K线列表,如果为None则使用默认处理结果
|
||||
|
||||
Returns:
|
||||
包含处理后K线的DataFrame
|
||||
"""
|
||||
if processed_klines is None:
|
||||
processed_klines = self.handle_containment()
|
||||
|
||||
data = []
|
||||
for kline in processed_klines:
|
||||
data.append({
|
||||
'timestamp': kline.timestamp,
|
||||
'open': kline.open,
|
||||
'high': kline.high,
|
||||
'low': kline.low,
|
||||
'close': kline.close,
|
||||
'volume': kline.volume,
|
||||
'direction': kline.direction
|
||||
})
|
||||
|
||||
df = pd.DataFrame(data)
|
||||
if not df.empty:
|
||||
df.set_index('timestamp', inplace=True)
|
||||
|
||||
return df
|
||||
|
||||
def get_processed_data(self) -> pd.DataFrame:
|
||||
"""
|
||||
获取处理包含关系后的数据
|
||||
|
||||
Returns:
|
||||
处理后的DataFrame
|
||||
"""
|
||||
if self.processed_data is None:
|
||||
processed_klines = self.handle_containment()
|
||||
self.processed_data = self.to_dataframe(processed_klines)
|
||||
|
||||
return self.processed_data
|
||||
|
||||
def visualize_containment(self) -> dict:
|
||||
"""
|
||||
生成包含关系可视化信息
|
||||
|
||||
Returns:
|
||||
包含可视化信息的字典
|
||||
"""
|
||||
original_count = len(self.kline_elements)
|
||||
processed_klines = self.handle_containment()
|
||||
processed_count = len(processed_klines)
|
||||
|
||||
return {
|
||||
'original_count': original_count,
|
||||
'processed_count': processed_count,
|
||||
'merged_count': original_count - processed_count,
|
||||
'merge_ratio': (original_count - processed_count) / original_count if original_count > 0 else 0
|
||||
}
|
||||
Reference in New Issue
Block a user