refactor: remove legacy trading engine, streamline project to weather-only bot
This commit is contained in:
@@ -1,95 +0,0 @@
|
||||
from loguru import logger
|
||||
|
||||
class OrderbookAnalyzer:
|
||||
"""
|
||||
分析目标: 评估市场供需平衡和流动性
|
||||
"""
|
||||
def __init__(self, config=None):
|
||||
self.config = config or {}
|
||||
self.wall_threshold = self.config.get("wall_threshold", 500) # 单笔订单超过此值为墙
|
||||
logger.info("Initializing Orderbook Analyzer...")
|
||||
|
||||
def assess_liquidity(self, orderbook, side="ask"):
|
||||
"""
|
||||
分析流动性深度 (基于前 3 档)
|
||||
"""
|
||||
orders = orderbook.get('asks' if side == "ask" else 'bids', [])
|
||||
if not orders:
|
||||
return "枯竭", 0
|
||||
|
||||
# 前 3 档总量 (Polymarket 通常返回价格字符串)
|
||||
depth = sum(float(o.get("size", 0)) for o in orders[:3])
|
||||
|
||||
if depth < 50:
|
||||
return "稀薄", depth
|
||||
elif depth < 500:
|
||||
return "正常", depth
|
||||
else:
|
||||
return "充裕", depth
|
||||
|
||||
def analyze(self, orderbook):
|
||||
"""
|
||||
增强版订单簿分析:集成深度与 Spread 评估
|
||||
"""
|
||||
bids = orderbook.get('bids', [])
|
||||
asks = orderbook.get('asks', [])
|
||||
|
||||
if not bids or not asks:
|
||||
return {
|
||||
"signal": "NEUTRAL",
|
||||
"confidence": 0.0,
|
||||
"tradeable": False,
|
||||
"reason": "缺乏双边报价",
|
||||
"liquidity": "枯竭",
|
||||
"spread": 1.0
|
||||
}
|
||||
|
||||
# 1. 计算核心指标
|
||||
best_bid = float(bids[0].get('price', 0))
|
||||
best_ask = float(asks[0].get('price', 0))
|
||||
spread = abs(best_ask - best_bid)
|
||||
mid_price = (best_ask + best_bid) / 2
|
||||
|
||||
# 2. 评估流动性
|
||||
ask_liq, ask_depth = self.assess_liquidity(orderbook, "ask")
|
||||
bid_liq, bid_depth = self.assess_liquidity(orderbook, "bid")
|
||||
|
||||
# 3. 交易可行性判定 (Spread <= 10c 且 深度 >= $50)
|
||||
is_tradeable = (spread <= 0.10) and (ask_depth >= 50 or bid_depth >= 50)
|
||||
|
||||
# 4. Imbalance 计算
|
||||
bid_volume = sum([float(b.get('size', 0)) for b in bids])
|
||||
ask_volume = sum([float(a.get('size', 0)) for a in asks])
|
||||
imbalance = bid_volume / ask_volume if ask_volume > 0 else 0
|
||||
|
||||
result = {
|
||||
"best_bid": best_bid,
|
||||
"best_ask": best_ask,
|
||||
"mid_price": mid_price,
|
||||
"spread": round(spread, 4),
|
||||
"ask_depth": round(ask_depth, 2),
|
||||
"bid_depth": round(bid_depth, 2),
|
||||
"liquidity": ask_liq if ask_depth < bid_depth else bid_liq,
|
||||
"tradeable": is_tradeable,
|
||||
"imbalance": imbalance,
|
||||
"signal": "NEUTRAL",
|
||||
"confidence": 0.5
|
||||
}
|
||||
|
||||
# 5. 信号修正
|
||||
if is_tradeable:
|
||||
if imbalance > 2.5:
|
||||
result["signal"] = "BULLISH"
|
||||
result["confidence"] = 0.75
|
||||
elif imbalance < 0.4:
|
||||
result["signal"] = "BEARISH"
|
||||
result["confidence"] = 0.75
|
||||
else:
|
||||
result["confidence"] = 0.1 # 不建议交易
|
||||
|
||||
return result
|
||||
|
||||
def analyze_orderbook(orderbook):
|
||||
"""兼容旧接口的便捷函数"""
|
||||
analyzer = OrderbookAnalyzer()
|
||||
return analyzer.analyze(orderbook)
|
||||
@@ -1,146 +0,0 @@
|
||||
import numpy as np
|
||||
from loguru import logger
|
||||
|
||||
class TechnicalIndicators:
|
||||
"""
|
||||
技术指标计算 - RSI, 布林带等
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
logger.info("Initializing Technical Indicators...")
|
||||
|
||||
def calculate_rsi(self, prices: list, period: int = 14) -> float:
|
||||
"""
|
||||
计算相对强弱指标 (RSI)
|
||||
|
||||
Args:
|
||||
prices: 价格历史列表
|
||||
period: RSI周期,默认14
|
||||
|
||||
Returns:
|
||||
float: RSI值 (0-100)
|
||||
"""
|
||||
if len(prices) < period + 1:
|
||||
logger.debug("Insufficient data for RSI calculation")
|
||||
return 50.0 # 返回中性值
|
||||
|
||||
prices = np.array(prices)
|
||||
deltas = np.diff(prices)
|
||||
|
||||
gains = np.where(deltas > 0, deltas, 0)
|
||||
losses = np.where(deltas < 0, -deltas, 0)
|
||||
|
||||
avg_gain = np.mean(gains[-period:])
|
||||
avg_loss = np.mean(losses[-period:])
|
||||
|
||||
if avg_loss == 0:
|
||||
return 100.0
|
||||
|
||||
rs = avg_gain / avg_loss
|
||||
rsi = 100 - (100 / (1 + rs))
|
||||
|
||||
logger.debug(f"RSI({period}): {rsi:.2f}")
|
||||
return rsi
|
||||
|
||||
def calculate_bollinger_bands(self, prices: list, period: int = 20, std_dev: float = 2.0) -> dict:
|
||||
"""
|
||||
计算布林带
|
||||
|
||||
Args:
|
||||
prices: 价格历史列表
|
||||
period: 移动平均周期
|
||||
std_dev: 标准差倍数
|
||||
|
||||
Returns:
|
||||
dict: 包含上轨、中轨、下轨
|
||||
"""
|
||||
if len(prices) < period:
|
||||
logger.debug("Insufficient data for Bollinger Bands")
|
||||
return {"upper": None, "middle": None, "lower": None}
|
||||
|
||||
prices = np.array(prices[-period:])
|
||||
middle = np.mean(prices)
|
||||
std = np.std(prices)
|
||||
|
||||
upper = middle + std_dev * std
|
||||
lower = middle - std_dev * std
|
||||
|
||||
return {
|
||||
"upper": upper,
|
||||
"middle": middle,
|
||||
"lower": lower,
|
||||
"std": std
|
||||
}
|
||||
|
||||
def calculate_momentum(self, prices: list, period: int = 10) -> float:
|
||||
"""
|
||||
计算价格动量
|
||||
|
||||
Args:
|
||||
prices: 价格历史
|
||||
period: 动量周期
|
||||
|
||||
Returns:
|
||||
float: 动量值 (当前价格 / N周期前价格 - 1)
|
||||
"""
|
||||
if len(prices) < period + 1:
|
||||
return 0.0
|
||||
|
||||
current = prices[-1]
|
||||
past = prices[-period - 1]
|
||||
|
||||
if past == 0:
|
||||
return 0.0
|
||||
|
||||
momentum = (current / past) - 1
|
||||
return momentum
|
||||
|
||||
def get_signal(self, prices: list) -> dict:
|
||||
"""
|
||||
综合技术指标信号
|
||||
|
||||
Returns:
|
||||
dict: 包含信号和分数
|
||||
"""
|
||||
rsi = self.calculate_rsi(prices)
|
||||
bb = self.calculate_bollinger_bands(prices)
|
||||
momentum = self.calculate_momentum(prices)
|
||||
|
||||
# RSI信号
|
||||
if rsi > 70:
|
||||
rsi_signal = "OVERBOUGHT"
|
||||
rsi_score = 0.3 # 超买,看跌
|
||||
elif rsi < 30:
|
||||
rsi_signal = "OVERSOLD"
|
||||
rsi_score = 0.8 # 超卖,看涨
|
||||
else:
|
||||
rsi_signal = "NEUTRAL"
|
||||
rsi_score = 0.5
|
||||
|
||||
# 布林带信号
|
||||
if bb["upper"] and len(prices) > 0:
|
||||
current_price = prices[-1]
|
||||
if current_price > bb["upper"]:
|
||||
bb_signal = "ABOVE_UPPER"
|
||||
bb_score = 0.7 # 突破上轨,强势
|
||||
elif current_price < bb["lower"]:
|
||||
bb_signal = "BELOW_LOWER"
|
||||
bb_score = 0.3 # 跌破下轨,弱势
|
||||
else:
|
||||
bb_signal = "WITHIN_BANDS"
|
||||
bb_score = 0.5
|
||||
else:
|
||||
bb_signal = "NO_DATA"
|
||||
bb_score = 0.5
|
||||
|
||||
# 综合分数
|
||||
combined_score = (rsi_score * 0.5 + bb_score * 0.3 +
|
||||
(0.5 + momentum * 2) * 0.2) # momentum 转换为 0-1
|
||||
combined_score = max(0, min(1, combined_score))
|
||||
|
||||
return {
|
||||
"rsi": {"value": rsi, "signal": rsi_signal, "score": rsi_score},
|
||||
"bollinger": {"bands": bb, "signal": bb_signal, "score": bb_score},
|
||||
"momentum": momentum,
|
||||
"combined_score": combined_score
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
import numpy as np
|
||||
from loguru import logger
|
||||
|
||||
class VolumeAnalyzer:
|
||||
"""
|
||||
交易量异常检测 - 识别聪明钱和市场转折点
|
||||
"""
|
||||
|
||||
def __init__(self, config=None):
|
||||
self.config = config or {}
|
||||
self.volume_threshold = self.config.get("volume_threshold", 2.0) # 2倍标准差
|
||||
self.large_order_threshold = self.config.get("large_order_threshold", 1000) # $1000
|
||||
logger.info("Initializing Volume Analyzer...")
|
||||
|
||||
def detect_volume_spike(self, volume_history: list) -> dict:
|
||||
"""
|
||||
检测成交量异常放大
|
||||
|
||||
Args:
|
||||
volume_history: 历史成交量列表
|
||||
|
||||
Returns:
|
||||
dict: 包含信号和置信度
|
||||
"""
|
||||
if len(volume_history) < 24:
|
||||
return {"signal": "INSUFFICIENT_DATA", "score": 0.5}
|
||||
|
||||
recent_volume = np.array(volume_history[-24:]) # 最近24小时
|
||||
historical_volume = np.array(volume_history[:-24])
|
||||
|
||||
if len(historical_volume) == 0:
|
||||
return {"signal": "INSUFFICIENT_DATA", "score": 0.5}
|
||||
|
||||
avg_volume = np.mean(historical_volume)
|
||||
std_volume = np.std(historical_volume)
|
||||
|
||||
recent_avg = np.mean(recent_volume)
|
||||
|
||||
# 计算Z-score
|
||||
if std_volume > 0:
|
||||
z_score = (recent_avg - avg_volume) / std_volume
|
||||
else:
|
||||
z_score = 0
|
||||
|
||||
logger.debug(f"Volume Z-score: {z_score:.2f}")
|
||||
|
||||
if z_score > self.volume_threshold:
|
||||
return {
|
||||
"signal": "VOLUME_SPIKE",
|
||||
"score": min(0.9, 0.5 + z_score * 0.1),
|
||||
"z_score": z_score,
|
||||
"interpretation": "成交量异常放大,可能有新信息进入市场"
|
||||
}
|
||||
elif z_score < -self.volume_threshold:
|
||||
return {
|
||||
"signal": "VOLUME_DRY",
|
||||
"score": 0.3,
|
||||
"z_score": z_score,
|
||||
"interpretation": "成交量萎缩,市场观望"
|
||||
}
|
||||
|
||||
return {"signal": "NORMAL", "score": 0.5, "z_score": z_score}
|
||||
|
||||
def detect_large_orders(self, transactions: list) -> dict:
|
||||
"""
|
||||
检测大额订单 (聪明钱信号)
|
||||
|
||||
Args:
|
||||
transactions: 交易列表,每个包含 size, side, price
|
||||
|
||||
Returns:
|
||||
dict: 大额订单分析结果
|
||||
"""
|
||||
large_buys = []
|
||||
large_sells = []
|
||||
|
||||
for tx in transactions:
|
||||
size = tx.get("size", 0)
|
||||
side = tx.get("side", "").upper()
|
||||
|
||||
if size >= self.large_order_threshold:
|
||||
if side == "BUY":
|
||||
large_buys.append(tx)
|
||||
elif side == "SELL":
|
||||
large_sells.append(tx)
|
||||
|
||||
total_large_buy = sum(t.get("size", 0) for t in large_buys)
|
||||
total_large_sell = sum(t.get("size", 0) for t in large_sells)
|
||||
|
||||
logger.debug(f"Large buys: ${total_large_buy:.2f}, Large sells: ${total_large_sell:.2f}")
|
||||
|
||||
if total_large_buy > total_large_sell * 2:
|
||||
return {
|
||||
"signal": "SMART_MONEY_BUY",
|
||||
"score": 0.8,
|
||||
"large_buy_volume": total_large_buy,
|
||||
"large_sell_volume": total_large_sell,
|
||||
"interpretation": "大户在积极买入,跟随机会"
|
||||
}
|
||||
elif total_large_sell > total_large_buy * 2:
|
||||
return {
|
||||
"signal": "SMART_MONEY_SELL",
|
||||
"score": 0.2,
|
||||
"large_buy_volume": total_large_buy,
|
||||
"large_sell_volume": total_large_sell,
|
||||
"interpretation": "大户在抛售,风险警告"
|
||||
}
|
||||
|
||||
return {
|
||||
"signal": "NEUTRAL",
|
||||
"score": 0.5,
|
||||
"large_buy_volume": total_large_buy,
|
||||
"large_sell_volume": total_large_sell
|
||||
}
|
||||
|
||||
def analyze(self, volume_history: list, transactions: list = None) -> dict:
|
||||
"""
|
||||
综合分析交易量
|
||||
"""
|
||||
volume_signal = self.detect_volume_spike(volume_history)
|
||||
|
||||
if transactions:
|
||||
order_signal = self.detect_large_orders(transactions)
|
||||
else:
|
||||
order_signal = {"signal": "NO_DATA", "score": 0.5}
|
||||
|
||||
# 综合评分
|
||||
combined_score = (volume_signal.get("score", 0.5) * 0.6 +
|
||||
order_signal.get("score", 0.5) * 0.4)
|
||||
|
||||
return {
|
||||
"volume_signal": volume_signal,
|
||||
"order_signal": order_signal,
|
||||
"combined_score": combined_score
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
from loguru import logger
|
||||
from typing import List, Dict
|
||||
from src.data_collection.onchain_tracker import OnchainTracker
|
||||
|
||||
class WhaleTracker:
|
||||
"""
|
||||
大户行为分析模块
|
||||
"""
|
||||
def __init__(self, config: dict, tracker: OnchainTracker):
|
||||
self.config = config
|
||||
self.tracker = tracker
|
||||
logger.info("Initializing Whale Tracker...")
|
||||
|
||||
def analyze_market_whales(self, market_id: str) -> Dict:
|
||||
"""
|
||||
分析特定市场的鲸鱼行为
|
||||
"""
|
||||
large_trades = self.tracker.get_large_transactions(market_id)
|
||||
|
||||
if not large_trades:
|
||||
return {"bullish": False, "signal": "NEUTRAL", "reason": "No whale activity detected"}
|
||||
|
||||
buy_value = 0
|
||||
sell_value = 0
|
||||
|
||||
for trade in large_trades:
|
||||
side = trade.get("side", "").upper()
|
||||
value = trade.get("value", 0)
|
||||
|
||||
if side == "BUY":
|
||||
buy_value += value
|
||||
else:
|
||||
sell_value += value
|
||||
|
||||
# 判断情绪
|
||||
if buy_value > sell_value * 2:
|
||||
return {
|
||||
"bullish": True,
|
||||
"signal": "STRONG_ACCUMULATION",
|
||||
"buy_value": buy_value,
|
||||
"sell_value": sell_value,
|
||||
"reason": "Whales are heavily buying"
|
||||
}
|
||||
elif sell_value > buy_value * 2:
|
||||
return {
|
||||
"bullish": False,
|
||||
"signal": "STRONG_DISTRIBUTION",
|
||||
"buy_value": buy_value,
|
||||
"sell_value": sell_value,
|
||||
"reason": "Whales are heavily selling"
|
||||
}
|
||||
|
||||
return {
|
||||
"bullish": buy_value > sell_value,
|
||||
"signal": "MODERATE",
|
||||
"buy_value": buy_value,
|
||||
"sell_value": sell_value,
|
||||
"reason": "Mixed whale activity"
|
||||
}
|
||||
Reference in New Issue
Block a user