Files
AI-Trader/market/store/pivot_store.py
T

145 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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