145 lines
5.0 KiB
Python
145 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
转折点存储模块
|
||
存储和管理转折点数据
|
||
"""
|
||
|
||
from collections import defaultdict
|
||
from datetime import datetime
|
||
from typing import List, Dict, Optional
|
||
import threading
|
||
|
||
from ..models import PivotPoint
|
||
|
||
|
||
class PivotStore:
|
||
"""转折点存储(只负责数据CRUD)"""
|
||
|
||
def __init__(self):
|
||
# 存储转折点: {SYMBOL: {PERIOD: [PivotPoint, ...]}}
|
||
self._pivots = defaultdict(lambda: defaultdict(list))
|
||
|
||
# 转折点时间线: {SYMBOL: {PERIOD: [PivotPoint, ...]}}
|
||
self._pivots_timeline = defaultdict(lambda: defaultdict(list))
|
||
|
||
self._lock = threading.RLock()
|
||
|
||
print("[PivotStore] 转折点存储已初始化")
|
||
|
||
def save_pivots(self, symbol: str, period: str, pivots: List[PivotPoint],
|
||
timeline: List[PivotPoint] = None):
|
||
"""
|
||
保存转折点数据
|
||
|
||
Args:
|
||
symbol: 交易品种
|
||
period: 周期
|
||
pivots: 合并后的转折点列表
|
||
timeline: 时间线转折点列表(可选)
|
||
"""
|
||
with self._lock:
|
||
self._pivots[symbol][period] = list(pivots)
|
||
if timeline is not None:
|
||
self._pivots_timeline[symbol][period] = list(timeline)
|
||
else:
|
||
self._pivots_timeline[symbol][period] = list(pivots)
|
||
|
||
def get_pivots(self, symbol: str, period: str, direction: str = None,
|
||
count: int = 50) -> List[Dict]:
|
||
"""获取转折点数据"""
|
||
with self._lock:
|
||
pivots = list(self._pivots[symbol][period])
|
||
|
||
if direction:
|
||
pivots = [p for p in pivots if p.direction == direction]
|
||
|
||
pivots = sorted(pivots, key=lambda x: str(x.timestamp), reverse=True)[:count]
|
||
return [p.to_dict() for p in pivots]
|
||
|
||
def get_pivot_objects(self, symbol: str, period: str = None) -> List[PivotPoint]:
|
||
"""获取转折点对象(用于内部计算)"""
|
||
with self._lock:
|
||
if period:
|
||
return list(self._pivots[symbol][period])
|
||
else:
|
||
# 返回所有周期
|
||
result = []
|
||
for p in self._pivots[symbol]:
|
||
result.extend(self._pivots[symbol][p])
|
||
return result
|
||
|
||
def get_timeline(self, symbol: str, period: str) -> List[PivotPoint]:
|
||
"""获取时间线转折点(用于判断趋势)"""
|
||
with self._lock:
|
||
return list(self._pivots_timeline[symbol][period])
|
||
|
||
def get_all_periods(self, symbol: str) -> List[str]:
|
||
"""获取有转折点数据的所有周期"""
|
||
with self._lock:
|
||
return list(self._pivots[symbol].keys())
|
||
|
||
def clear_symbol(self, symbol: str):
|
||
"""清除某个Symbol的转折点数据"""
|
||
with self._lock:
|
||
if symbol in self._pivots:
|
||
del self._pivots[symbol]
|
||
if symbol in self._pivots_timeline:
|
||
del self._pivots_timeline[symbol]
|
||
|
||
def get_status(self) -> Dict:
|
||
"""获取状态"""
|
||
with self._lock:
|
||
status = {}
|
||
for symbol in self._pivots:
|
||
status[symbol] = {}
|
||
for period in self._pivots[symbol]:
|
||
count = len(self._pivots[symbol][period])
|
||
status[symbol][period] = {"pivot_count": count}
|
||
return status
|
||
|
||
def find_nearest_pivot_price(self, symbol: str, direction: str,
|
||
current_price: float) -> Optional[float]:
|
||
"""
|
||
找到离当前价格最近的转折点价格
|
||
|
||
Args:
|
||
symbol: 交易品种
|
||
direction: 'high' 或 'low'
|
||
current_price: 当前价格
|
||
|
||
Returns:
|
||
最近的转折点价格,如果没有返回None
|
||
"""
|
||
nearest_price = None
|
||
min_distance = float('inf')
|
||
total_pivots = 0
|
||
filtered_pivots = 0
|
||
|
||
with self._lock:
|
||
for period in self._pivots[symbol]:
|
||
pivots = self._pivots[symbol][period]
|
||
total_pivots += len(pivots)
|
||
|
||
for pivot in pivots:
|
||
if pivot.direction != direction:
|
||
continue
|
||
|
||
if direction == 'high' and pivot.price <= current_price:
|
||
filtered_pivots += 1
|
||
continue
|
||
if direction == 'low' and pivot.price >= current_price:
|
||
filtered_pivots += 1
|
||
continue
|
||
|
||
distance = abs(pivot.price - current_price)
|
||
if distance < min_distance:
|
||
min_distance = distance
|
||
nearest_price = pivot.price
|
||
|
||
if nearest_price is None and total_pivots > 0:
|
||
print(f"[PivotStore] find_nearest_pivot_price: 未找到 {direction} 转折点, "
|
||
f"current_price={current_price:.2f}, "
|
||
f"total_pivots={total_pivots}, filtered={filtered_pivots}")
|
||
|
||
return nearest_price |