This commit is contained in:
aaron 2025-12-04 00:38:23 +08:00
parent ef36140353
commit 51694bc787
5 changed files with 385 additions and 321 deletions

View File

@ -2,7 +2,7 @@
LLM Context Builder - Generate structured market analysis for LLM decision making LLM Context Builder - Generate structured market analysis for LLM decision making
""" """
import logging import logging
from typing import Dict, Any, Optional from typing import Dict, Any, Optional, List
from datetime import datetime from datetime import datetime
import pandas as pd import pandas as pd
@ -21,6 +21,17 @@ from signals.quantitative import QuantitativeSignalGenerator
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# K线数量配置 - 按时间周期不同
KLINE_LIMITS = {
'5m': 288, # 1天 = 24*60/5 = 288 根
'15m': 96, # 1天 = 24*60/15 = 96 根
'1h': 72, # 3天 = 3*24 = 72 根
'4h': 18, # 3天 = 3*24/4 = 18 根
'1d': 30, # 30天
'1w': 60, # 60周
}
class LLMContextBuilder: class LLMContextBuilder:
"""Build structured context for LLM trading decisions""" """Build structured context for LLM trading decisions"""
@ -38,8 +49,8 @@ class LLMContextBuilder:
Dict with structured market analysis Dict with structured market analysis
""" """
try: try:
# Fetch multi-timeframe data # Fetch multi-timeframe data with custom limits
mtf_data = self.data_reader.get_multi_timeframe_data() mtf_data = self._get_multi_timeframe_data_for_llm()
if '5m' not in mtf_data or mtf_data['5m'].empty: if '5m' not in mtf_data or mtf_data['5m'].empty:
logger.error("No 5m data available for analysis") logger.error("No 5m data available for analysis")
@ -57,17 +68,17 @@ class LLMContextBuilder:
# Fetch order book data # Fetch order book data
depth_data = self.data_reader.read_latest_depth() depth_data = self.data_reader.read_latest_depth()
# Build context sections # Build context sections (移除支撑位压力位计算)
context = { context = {
'timestamp': datetime.now().isoformat(), 'timestamp': datetime.now().isoformat(),
'symbol': symbol, 'symbol': symbol,
'current_price': round(current_price, 2), 'current_price': round(current_price, 2),
'market_state': self._build_market_state(df_5m, mtf_data), 'market_state': self._build_market_state(df_5m, mtf_data),
'key_prices': self._build_key_prices(df_5m, current_price),
'momentum': self._build_momentum_analysis(df_5m, depth_data), 'momentum': self._build_momentum_analysis(df_5m, depth_data),
'volatility_analysis': self._build_volatility_analysis(df_5m), 'volatility_analysis': self._build_volatility_analysis(df_5m),
'volume_analysis': self._build_volume_analysis(df_5m), 'volume_analysis': self._build_volume_analysis(df_5m),
'multi_timeframe': self._build_mtf_summary(mtf_data), 'multi_timeframe': self._build_mtf_summary(mtf_data),
'kline_data': self._build_kline_data(mtf_data), # 新增 K 线数据
'signal_consensus': self._calculate_signal_consensus(df_5m, depth_data), 'signal_consensus': self._calculate_signal_consensus(df_5m, depth_data),
'risk_metrics': self._build_risk_metrics(df_5m, current_price), 'risk_metrics': self._build_risk_metrics(df_5m, current_price),
} }
@ -79,6 +90,68 @@ class LLMContextBuilder:
logger.error(f"Error building LLM context: {e}", exc_info=True) logger.error(f"Error building LLM context: {e}", exc_info=True)
return self._empty_context() return self._empty_context()
def _get_multi_timeframe_data_for_llm(self) -> Dict[str, pd.DataFrame]:
"""
Fetch data from multiple timeframes with custom limits for LLM
Returns:
Dict mapping timeframe to DataFrame
"""
from .config import config as analysis_config
timeframes = {
'5m': (analysis_config.KLINE_5M_KEY, KLINE_LIMITS['5m']),
'15m': (analysis_config.KLINE_15M_KEY, KLINE_LIMITS['15m']),
'1h': (analysis_config.KLINE_1H_KEY, KLINE_LIMITS['1h']),
'4h': (analysis_config.KLINE_4H_KEY, KLINE_LIMITS['4h']),
'1d': (analysis_config.KLINE_1D_KEY, KLINE_LIMITS['1d']),
'1w': (analysis_config.KLINE_1W_KEY, KLINE_LIMITS['1w']),
}
data = {}
for tf, (key, count) in timeframes.items():
df = self.data_reader.read_kline_stream(key, count=count)
if not df.empty:
data[tf] = df
return data
def _build_kline_data(self, mtf_data: Dict[str, pd.DataFrame]) -> Dict[str, List[Dict]]:
"""
Build K-line data for LLM analysis
不同时间周期提供不同数量的K线数据
Returns:
Dict mapping timeframe to list of kline dicts
"""
kline_data = {}
for timeframe, df in mtf_data.items():
if df.empty:
continue
# 获取该周期需要的K线数量
limit = KLINE_LIMITS.get(timeframe, 50)
# 取最近的N根K线
df_limited = df.tail(limit)
# 转换为简洁格式
klines = []
for idx, row in df_limited.iterrows():
klines.append({
't': idx.strftime('%Y-%m-%d %H:%M'), # 时间
'o': round(row['open'], 2), # 开盘价
'h': round(row['high'], 2), # 最高价
'l': round(row['low'], 2), # 最低价
'c': round(row['close'], 2), # 收盘价
'v': round(row['volume'], 2), # 成交量
})
kline_data[timeframe] = klines
return kline_data
def _build_market_state( def _build_market_state(
self, df: pd.DataFrame, mtf_data: Dict[str, pd.DataFrame] self, df: pd.DataFrame, mtf_data: Dict[str, pd.DataFrame]
) -> Dict[str, Any]: ) -> Dict[str, Any]:
@ -113,32 +186,6 @@ class LLMContextBuilder:
'higher_timeframe_alignment': htf_alignment, 'higher_timeframe_alignment': htf_alignment,
} }
def _build_key_prices(self, df: pd.DataFrame, current_price: float) -> Dict[str, Any]:
"""Build key price levels section"""
sr_levels = MarketStructureAnalyzer.find_support_resistance(df, current_price)
breakout_info = MarketStructureAnalyzer.detect_breakout(df, sr_levels)
# Format prices
support_str = f"${sr_levels['nearest_support']:,.0f}" if sr_levels.get('nearest_support') else "无明显支撑"
resistance_str = f"${sr_levels['nearest_resistance']:,.0f}" if sr_levels.get('nearest_resistance') else "无明显压力"
# Get Bollinger Bands
latest = df.iloc[-1]
bb_upper = latest.get('bb_upper')
bb_lower = latest.get('bb_lower')
return {
'support': support_str,
'support_level': sr_levels.get('nearest_support'),
'resistance': resistance_str,
'resistance_level': sr_levels.get('nearest_resistance'),
'all_support_levels': sr_levels.get('support', []),
'all_resistance_levels': sr_levels.get('resistance', []),
'breakout_status': breakout_info,
'bollinger_upper': round(bb_upper, 2) if bb_upper else None,
'bollinger_lower': round(bb_lower, 2) if bb_lower else None,
}
def _build_momentum_analysis( def _build_momentum_analysis(
self, df: pd.DataFrame, depth_data: Optional[Dict[str, Any]] self, df: pd.DataFrame, depth_data: Optional[Dict[str, Any]]
) -> Dict[str, Any]: ) -> Dict[str, Any]:
@ -243,25 +290,22 @@ class LLMContextBuilder:
# Get momentum # Get momentum
momentum = MarketStructureAnalyzer.calculate_momentum(df) momentum = MarketStructureAnalyzer.calculate_momentum(df)
# Get support/resistance # Get ATR (不再计算支撑位压力位)
sr_levels = MarketStructureAnalyzer.find_support_resistance(df, current_price)
# Get ATR
atr = latest.get('atr', 0) atr = latest.get('atr', 0)
atr_pct = (atr / current_price * 100) if current_price > 0 else 0 atr_pct = (atr / current_price * 100) if current_price > 0 else 0
# Get volume ratio # Get volume ratio
volume_ratio = latest.get('volume_ratio', 1) volume_ratio = latest.get('volume_ratio', 1)
# ===== NEW: Calculate quantitative scores for this timeframe ===== # ===== Calculate quantitative scores for this timeframe =====
# Build mini analysis for this timeframe # Build mini analysis for this timeframe (不包含支撑位压力位)
mini_analysis = { mini_analysis = {
'current_price': current_price, 'current_price': current_price,
'trend_analysis': trend_info, 'trend_analysis': trend_info,
'momentum': momentum, 'momentum': momentum,
'support_resistance': sr_levels, 'support_resistance': {'support': [], 'resistance': [], 'nearest_support': None, 'nearest_resistance': None},
'breakout': {'has_breakout': False}, # Simplified for now 'breakout': {'has_breakout': False},
'orderflow': None, # Orderflow only for 5m 'orderflow': None,
'indicators': {'atr': atr} 'indicators': {'atr': atr}
} }
@ -303,10 +347,6 @@ class LLMContextBuilder:
'macd_signal': momentum.get('macd_signal', 'unknown'), 'macd_signal': momentum.get('macd_signal', 'unknown'),
'macd_hist': round(momentum.get('macd_hist', 0), 2), 'macd_hist': round(momentum.get('macd_hist', 0), 2),
# Support/Resistance
'support': sr_levels.get('nearest_support'),
'resistance': sr_levels.get('nearest_resistance'),
# Volatility # Volatility
'atr': round(atr, 2), 'atr': round(atr, 2),
'atr_pct': round(atr_pct, 2), 'atr_pct': round(atr_pct, 2),
@ -314,7 +354,7 @@ class LLMContextBuilder:
# Volume # Volume
'volume_ratio': round(volume_ratio, 2), 'volume_ratio': round(volume_ratio, 2),
# ===== NEW: Quantitative scores ===== # Quantitative scores
'quantitative': quant_scores, 'quantitative': quant_scores,
} }
@ -465,7 +505,6 @@ class LLMContextBuilder:
'timestamp': datetime.now().isoformat(), 'timestamp': datetime.now().isoformat(),
'error': 'Insufficient data for analysis', 'error': 'Insufficient data for analysis',
'market_state': {}, 'market_state': {},
'key_prices': {},
'momentum': {}, 'momentum': {},
'signal_consensus': 0.5, 'signal_consensus': 0.5,
} }
@ -482,17 +521,13 @@ class LLMContextBuilder:
if 'error' in full_context: if 'error' in full_context:
return full_context return full_context
# Extract and simplify to match user's example # Extract and simplify (不再包含支撑位压力位)
return { return {
'market_state': { 'market_state': {
'trend_direction': full_context['market_state']['trend_direction'], 'trend_direction': full_context['market_state']['trend_direction'],
'market_phase': full_context['market_state']['market_phase'], 'market_phase': full_context['market_state']['market_phase'],
'volatility': full_context['market_state']['volatility'], 'volatility': full_context['market_state']['volatility'],
}, },
'key_prices': {
'support': full_context['key_prices']['support'],
'resistance': full_context['key_prices']['resistance'],
},
'momentum': { 'momentum': {
'rsi_status': full_context['momentum']['rsi_status'], 'rsi_status': full_context['momentum']['rsi_status'],
'macd': full_context['momentum']['macd'], 'macd': full_context['momentum']['macd'],

View File

@ -71,5 +71,9 @@ class Settings(BaseSettings):
LLM_MAX_CALLS_PER_DAY: int = 12 # 每天最多调用次数 LLM_MAX_CALLS_PER_DAY: int = 12 # 每天最多调用次数
LLM_MIN_INTERVAL_MINUTES: int = 15 # 最小调用间隔(分钟) LLM_MIN_INTERVAL_MINUTES: int = 15 # 最小调用间隔(分钟)
# 盈利空间过滤(过滤低利润机会)
MIN_PROFIT_PCT: float = 1.0 # 最小盈利空间百分比,低于此值的机会不给操作建议
PREFER_INTRADAY: bool = True # 优先日内短线交易建议
settings = Settings() settings = Settings()

View File

@ -1,43 +1,43 @@
{ {
"timestamp": "2025-12-02T14:50:51.220024", "timestamp": "2025-12-03T16:25:01.783326",
"aggregated_signal": { "aggregated_signal": {
"timestamp": "2025-12-02T14:50:51.218349", "timestamp": "2025-12-03T16:25:01.781521",
"final_signal": "HOLD", "final_signal": "HOLD",
"final_confidence": 0.3, "final_confidence": 0.58,
"consensus": "CONSENSUS_HOLD", "consensus": "CONSENSUS_HOLD",
"agreement_score": 0.3, "agreement_score": 0.58,
"quantitative_signal": { "quantitative_signal": {
"signal_type": "HOLD", "signal_type": "HOLD",
"signal": "HOLD", "signal": "HOLD",
"confidence": 0.0, "confidence": 0.5,
"composite_score": 17.5, "composite_score": -12.8,
"scores": { "scores": {
"trend": 0.0, "trend": -23.1,
"momentum": -30, "momentum": -65,
"orderflow": 100, "orderflow": 46.3,
"breakout": 0 "breakout": 0
} }
}, },
"llm_signal": { "llm_signal": {
"signal_type": "HOLD", "signal_type": "HOLD",
"signal": "HOLD", "signal": "HOLD",
"confidence": 0.6, "confidence": 0.67,
"reasoning": "多周期分析显示市场处于严重分歧状态短期5m/15m强劲看涨中期4h/1d明确看跌长期1d/1w方向矛盾。这种分歧导致整体信号为HOLD。短期上涨面临中期趋势阻力和超买技术指标压制上行空间可能受限。交易机会仅限于快进快出的日内多头中长线需等待趋势共振。", "reasoning": "多周期综合分析显示市场处于关键分歧点。短期1h与超短期5m/15m趋势不一致中期4h与1d趋势完全相反长期1d与1w趋势也存在矛盾。各周期未能形成共振市场缺乏统一方向呈现震荡格局。当前价格位于多个周期的关键位之间方向选择有待确认。",
"key_factors": [ "key_factors": [
"多周期趋势严重分歧", "多周期趋势严重分歧,方向不明",
"短期RSI超买与中期下跌趋势冲突", "成交量普遍萎缩,市场动能不足",
"价格处于4小时关键压力位$89,177", "价格位于关键支撑与压力区间内震荡",
"成交量在短期放量但日线缩量", "大周期日线、周线MACD信号矛盾",
"周线长期趋势方向待定" "市场等待突破以选择后续方向"
], ],
"opportunities": { "opportunities": {
"short_term_5m_15m_1h": { "short_term_5m_15m_1h": {
"exists": true, "exists": false,
"direction": "LONG", "direction": null,
"entry_price": 89158.5, "entry_price": 0,
"stop_loss": 88800.0, "stop_loss": 0,
"take_profit": 91592.0, "take_profit": 0,
"reasoning": "5m和15m周期呈现强劲上涨趋势量化评分28.4/40.9MACD金叉成交量放大但RSI均超买>80。1h周期趋势下跌但MACD金叉扩大价格接近1h压力位$91,592。短期存在基于小周期动量延续的做多机会但需警惕超买回调风险。" "reasoning": "短期周期趋势分歧。5m和15m显示下跌趋势量化评分-24.3但1h显示上涨趋势量化评分23.4。动量指标MACD死叉与部分趋势信号矛盾RSI处于中性区域成交量萎缩缺乏明确的共振入场信号。价格在1h支撑$91,637和压力$92,273之间震荡方向不明。"
}, },
"medium_term_4h_1d": { "medium_term_4h_1d": {
"exists": false, "exists": false,
@ -45,7 +45,7 @@
"entry_price": 0, "entry_price": 0,
"stop_loss": 0, "stop_loss": 0,
"take_profit": 0, "take_profit": 0,
"reasoning": "4h和1d周期均显示强劲下跌趋势量化评分-33.4/-23.4与短期上涨趋势形成严重分歧。4h压力位$89,177与当前价格$89,158.5几乎重合构成关键阻力。日线MACD虽金叉但趋势向下RSI中性偏弱缺乏明确的中期反转或延续信号建议观望。" "reasoning": "中期周期趋势严重分歧。4h周期显示上涨趋势量化评分29.3趋势强度moderateRSI 60.2强势但1d周期显示下跌趋势量化评分-23.4趋势强度strong。MACD信号不一致4h金叉收窄1d金叉扩大价格接近4h压力位$93,080但未突破。成交量萎缩市场缺乏明确的波段方向动能建议观望等待趋势统一。"
}, },
"long_term_1d_1w": { "long_term_1d_1w": {
"exists": false, "exists": false,
@ -53,20 +53,20 @@
"entry_price": 0, "entry_price": 0,
"stop_loss": 0, "stop_loss": 0,
"take_profit": 0, "take_profit": 0,
"reasoning": "日线下跌趋势与周线上涨趋势方向严重冲突。周线量化评分仅4.3信号模糊MACD死叉扩大RSI弱势。日线趋势向下但MACD金叉显示长期趋势不明朗处于关键抉择期。无明确的长期趋势交易机会需等待日线与周线趋势共振。" "reasoning": "长期周期趋势存在分歧。1d周期显示下跌趋势趋势强度strong而1w周期显示上涨趋势趋势强度moderate。量化评分方向不一致1d: -23.4, 1w: 11.8。周线MACD仍为死叉尽管收窄日线MACD为金叉信号矛盾。价格位于周线支撑$91,130上方但未形成明确的大周期共振趋势缺乏长期布局的清晰入场点。"
}, },
"ambush": { "ambush": {
"exists": true, "exists": true,
"price_level": 86207.0, "price_level": 91130.0,
"reasoning": "等待价格回调至1h关键支撑位$86,207附近。该位置接近4h支撑$86,261若价格能在此企稳并出现1h或4h周期的反弹信号如RSI从超卖区回升、MACD金叉可考虑作为中期做多埋伏点博弈日线下跌趋势中的反弹或反转。" "reasoning": "基于周线关键支撑位$91,130设置埋伏。若价格回调至此位置并伴随1h或4h周期出现明确的反弹反转信号如RSI超卖反弹、MACD金叉、放量可考虑分批布局多单博弈周线级别上涨趋势的延续。"
}, },
"intraday": { "intraday": {
"exists": true, "exists": false,
"direction": "LONG", "direction": null,
"entry_price": 89158.5, "entry_price": 0,
"stop_loss": 88800.0, "stop_loss": 0,
"take_profit": 91592.0, "take_profit": 0,
"reasoning": "5m和15m周期呈现强劲上涨趋势量化评分28.4/40.9MACD金叉成交量放大但RSI均超买>80。1h周期趋势下跌但MACD金叉扩大价格接近1h压力位$91,592。短期存在基于小周期动量延续的做多机会但需警惕超买回调风险。" "reasoning": "短期周期趋势分歧。5m和15m显示下跌趋势量化评分-24.3但1h显示上涨趋势量化评分23.4。动量指标MACD死叉与部分趋势信号矛盾RSI处于中性区域成交量萎缩缺乏明确的共振入场信号。价格在1h支撑$91,637和压力$92,273之间震荡方向不明。"
}, },
"swing": { "swing": {
"exists": false, "exists": false,
@ -74,88 +74,84 @@
"entry_price": 0, "entry_price": 0,
"stop_loss": 0, "stop_loss": 0,
"take_profit": 0, "take_profit": 0,
"reasoning": "4h和1d周期均显示强劲下跌趋势量化评分-33.4/-23.4与短期上涨趋势形成严重分歧。4h压力位$89,177与当前价格$89,158.5几乎重合构成关键阻力。日线MACD虽金叉但趋势向下RSI中性偏弱缺乏明确的中期反转或延续信号建议观望。" "reasoning": "中期周期趋势严重分歧。4h周期显示上涨趋势量化评分29.3趋势强度moderateRSI 60.2强势但1d周期显示下跌趋势量化评分-23.4趋势强度strong。MACD信号不一致4h金叉收窄1d金叉扩大价格接近4h压力位$93,080但未突破。成交量萎缩市场缺乏明确的波段方向动能建议观望等待趋势统一。"
} }
}, },
"recommendations_by_timeframe": { "recommendations_by_timeframe": {
"short_term": "短期(5m/15m/1h)存在基于小周期动量的日内做多机会但RSI已严重超买风险较高。建议轻仓快进快出严格设置止损于$88,800基于5m ATR目标看向1h压力位$91,592。若价格无法有效突破当前4h压力$89,177应果断离场。", "short_term": "短期(5m/15m/1h)操作建议观望。当前5m/15m与1h趋势方向矛盾市场处于震荡整理状态缺乏清晰的日内交易机会。可关注价格对1h支撑$91,637和压力$92,273的突破情况等待小周期形成共振后再考虑入场。",
"medium_term": "中期(4h/1d)趋势向下但当前价格处于4h关键压力位且与短期上涨动能背离。无明确的中期波段入场点建议观望。可关注价格能否站稳$89,177上方以挑战日线压力$93,080或回落至$86,200-$86,800支撑区域寻找企稳信号。", "medium_term": "中期(4h/1d)操作建议观望。4h看涨与1d看跌形成强烈分歧市场方向不明。建议等待价格有效突破4h压力$93,080确认中期转强或跌破4h支撑$90,612确认中期转弱并结合成交量放大信号再寻找波段交易机会。",
"long_term": "长期(1d/1w)趋势矛盾,日线下跌与周线上涨形成拉锯。周线支撑$88,909已被短暂跌破长期方向待定。建议长期投资者保持观望等待日线趋势当前下跌与周线趋势当前上涨出现明确一致信号后再做布局或利用ambush点位分批建仓。" "long_term": "长期(1d/1w)操作建议:观望。日线与周线趋势不一致,长期趋势未明朗。可关注周线支撑$91,130的防守情况。若价格能站稳该支撑并推动日线趋势转涨形成大周期共振则可能开启长期上涨趋势反之若跌破则长期趋势可能转弱。目前宜耐心等待更明确的趋势信号。"
}, },
"trade_type": "MULTI_TIMEFRAME", "trade_type": "MULTI_TIMEFRAME",
"risk_level": "HIGH" "risk_level": "MEDIUM"
}, },
"levels": { "levels": {
"current_price": 89179.2, "current_price": 92028.4,
"entry": 89179.2, "entry": 92028.4,
"stop_loss": 88999.95, "stop_loss": 92028.4,
"take_profit_1": 90395.95, "take_profit_1": 92028.4,
"take_profit_2": 90395.95, "take_profit_2": 92028.4,
"take_profit_3": 90395.95, "take_profit_3": 92028.4
"take_profit_1_range": {
"quant": 89199.9,
"llm": 91592.0,
"diff_pct": 2.65
}
}, },
"risk_reward_ratio": 6.79, "risk_reward_ratio": 0,
"recommendation": "量化和AI分析均建议观望,等待更好的机会", "recommendation": "量化和AI分析均建议观望,等待更好的机会",
"warnings": [ "warnings": []
"⚠️ 量化信号置信度较低"
]
}, },
"market_analysis": { "market_analysis": {
"price": 89199.9, "price": 92028.4,
"trend": { "trend": {
"direction": "unknown", "direction": "下跌",
"strength": 0 "strength": "weak",
"phase": "下跌中",
"adx": 12.9,
"ema_alignment": "bearish"
}, },
"momentum": { "momentum": {
"rsi": 50, "rsi": 44.0,
"rsi_status": "中性偏弱", "rsi_status": "中性偏弱",
"rsi_trend": "", "rsi_trend": "下降中",
"macd_signal": "死叉收窄", "macd_signal": "死叉扩大",
"macd_hist": 0 "macd_hist": -23.7636
} }
}, },
"quantitative_signal": { "quantitative_signal": {
"timestamp": "2025-12-02T14:50:04.306308", "timestamp": "2025-12-03T16:24:23.426153",
"signal_type": "HOLD", "signal_type": "HOLD",
"signal_strength": 0.17, "signal_strength": 0.13,
"composite_score": 17.5, "composite_score": -12.8,
"confidence": 0.0, "confidence": 0.5,
"consensus_score": 0.0, "consensus_score": 0.7,
"scores": { "scores": {
"trend": 0.0, "trend": -23.1,
"momentum": -30, "momentum": -65,
"orderflow": 100, "orderflow": 46.3,
"breakout": 0 "breakout": 0
}, },
"levels": { "levels": {
"current_price": 89199.9, "current_price": 92028.4,
"entry": 89199.9, "entry": 92028.4,
"stop_loss": 89199.9, "stop_loss": 92028.4,
"take_profit_1": 89199.9, "take_profit_1": 92028.4,
"take_profit_2": 89199.9, "take_profit_2": 92028.4,
"take_profit_3": 89199.9 "take_profit_3": 92028.4
}, },
"risk_reward_ratio": 0, "risk_reward_ratio": 0,
"reasoning": "趋势unknown (0); RSI=50; MACD 死叉收窄; 订单流: 强买方主导" "reasoning": "趋势下跌 (weak); RSI=44; MACD 死叉扩大; 订单流: 强买方主导"
}, },
"llm_signal": { "llm_signal": {
"timestamp": "2025-12-02T14:50:51.218012", "timestamp": "2025-12-03T16:25:01.781138",
"signal_type": "HOLD", "signal_type": "HOLD",
"confidence": 0.6, "confidence": 0.67,
"trade_type": "MULTI_TIMEFRAME", "trade_type": "MULTI_TIMEFRAME",
"reasoning": "多周期分析显示市场处于严重分歧状态短期5m/15m强劲看涨中期4h/1d明确看跌长期1d/1w方向矛盾。这种分歧导致整体信号为HOLD。短期上涨面临中期趋势阻力和超买技术指标压制上行空间可能受限。交易机会仅限于快进快出的日内多头中长线需等待趋势共振。", "reasoning": "多周期综合分析显示市场处于关键分歧点。短期1h与超短期5m/15m趋势不一致中期4h与1d趋势完全相反长期1d与1w趋势也存在矛盾。各周期未能形成共振市场缺乏统一方向呈现震荡格局。当前价格位于多个周期的关键位之间方向选择有待确认。",
"opportunities": { "opportunities": {
"short_term_5m_15m_1h": { "short_term_5m_15m_1h": {
"exists": true, "exists": false,
"direction": "LONG", "direction": null,
"entry_price": 89158.5, "entry_price": 0,
"stop_loss": 88800.0, "stop_loss": 0,
"take_profit": 91592.0, "take_profit": 0,
"reasoning": "5m和15m周期呈现强劲上涨趋势量化评分28.4/40.9MACD金叉成交量放大但RSI均超买>80。1h周期趋势下跌但MACD金叉扩大价格接近1h压力位$91,592。短期存在基于小周期动量延续的做多机会但需警惕超买回调风险。" "reasoning": "短期周期趋势分歧。5m和15m显示下跌趋势量化评分-24.3但1h显示上涨趋势量化评分23.4。动量指标MACD死叉与部分趋势信号矛盾RSI处于中性区域成交量萎缩缺乏明确的共振入场信号。价格在1h支撑$91,637和压力$92,273之间震荡方向不明。"
}, },
"medium_term_4h_1d": { "medium_term_4h_1d": {
"exists": false, "exists": false,
@ -163,7 +159,7 @@
"entry_price": 0, "entry_price": 0,
"stop_loss": 0, "stop_loss": 0,
"take_profit": 0, "take_profit": 0,
"reasoning": "4h和1d周期均显示强劲下跌趋势量化评分-33.4/-23.4与短期上涨趋势形成严重分歧。4h压力位$89,177与当前价格$89,158.5几乎重合构成关键阻力。日线MACD虽金叉但趋势向下RSI中性偏弱缺乏明确的中期反转或延续信号建议观望。" "reasoning": "中期周期趋势严重分歧。4h周期显示上涨趋势量化评分29.3趋势强度moderateRSI 60.2强势但1d周期显示下跌趋势量化评分-23.4趋势强度strong。MACD信号不一致4h金叉收窄1d金叉扩大价格接近4h压力位$93,080但未突破。成交量萎缩市场缺乏明确的波段方向动能建议观望等待趋势统一。"
}, },
"long_term_1d_1w": { "long_term_1d_1w": {
"exists": false, "exists": false,
@ -171,20 +167,20 @@
"entry_price": 0, "entry_price": 0,
"stop_loss": 0, "stop_loss": 0,
"take_profit": 0, "take_profit": 0,
"reasoning": "日线下跌趋势与周线上涨趋势方向严重冲突。周线量化评分仅4.3信号模糊MACD死叉扩大RSI弱势。日线趋势向下但MACD金叉显示长期趋势不明朗处于关键抉择期。无明确的长期趋势交易机会需等待日线与周线趋势共振。" "reasoning": "长期周期趋势存在分歧。1d周期显示下跌趋势趋势强度strong而1w周期显示上涨趋势趋势强度moderate。量化评分方向不一致1d: -23.4, 1w: 11.8。周线MACD仍为死叉尽管收窄日线MACD为金叉信号矛盾。价格位于周线支撑$91,130上方但未形成明确的大周期共振趋势缺乏长期布局的清晰入场点。"
}, },
"ambush": { "ambush": {
"exists": true, "exists": true,
"price_level": 86207.0, "price_level": 91130.0,
"reasoning": "等待价格回调至1h关键支撑位$86,207附近。该位置接近4h支撑$86,261若价格能在此企稳并出现1h或4h周期的反弹信号如RSI从超卖区回升、MACD金叉可考虑作为中期做多埋伏点博弈日线下跌趋势中的反弹或反转。" "reasoning": "基于周线关键支撑位$91,130设置埋伏。若价格回调至此位置并伴随1h或4h周期出现明确的反弹反转信号如RSI超卖反弹、MACD金叉、放量可考虑分批布局多单博弈周线级别上涨趋势的延续。"
}, },
"intraday": { "intraday": {
"exists": true, "exists": false,
"direction": "LONG", "direction": null,
"entry_price": 89158.5, "entry_price": 0,
"stop_loss": 88800.0, "stop_loss": 0,
"take_profit": 91592.0, "take_profit": 0,
"reasoning": "5m和15m周期呈现强劲上涨趋势量化评分28.4/40.9MACD金叉成交量放大但RSI均超买>80。1h周期趋势下跌但MACD金叉扩大价格接近1h压力位$91,592。短期存在基于小周期动量延续的做多机会但需警惕超买回调风险。" "reasoning": "短期周期趋势分歧。5m和15m显示下跌趋势量化评分-24.3但1h显示上涨趋势量化评分23.4。动量指标MACD死叉与部分趋势信号矛盾RSI处于中性区域成交量萎缩缺乏明确的共振入场信号。价格在1h支撑$91,637和压力$92,273之间震荡方向不明。"
}, },
"swing": { "swing": {
"exists": false, "exists": false,
@ -192,31 +188,31 @@
"entry_price": 0, "entry_price": 0,
"stop_loss": 0, "stop_loss": 0,
"take_profit": 0, "take_profit": 0,
"reasoning": "4h和1d周期均显示强劲下跌趋势量化评分-33.4/-23.4与短期上涨趋势形成严重分歧。4h压力位$89,177与当前价格$89,158.5几乎重合构成关键阻力。日线MACD虽金叉但趋势向下RSI中性偏弱缺乏明确的中期反转或延续信号建议观望。" "reasoning": "中期周期趋势严重分歧。4h周期显示上涨趋势量化评分29.3趋势强度moderateRSI 60.2强势但1d周期显示下跌趋势量化评分-23.4趋势强度strong。MACD信号不一致4h金叉收窄1d金叉扩大价格接近4h压力位$93,080但未突破。成交量萎缩市场缺乏明确的波段方向动能建议观望等待趋势统一。"
} }
}, },
"recommendations_by_timeframe": { "recommendations_by_timeframe": {
"short_term": "短期(5m/15m/1h)存在基于小周期动量的日内做多机会但RSI已严重超买风险较高。建议轻仓快进快出严格设置止损于$88,800基于5m ATR目标看向1h压力位$91,592。若价格无法有效突破当前4h压力$89,177应果断离场。", "short_term": "短期(5m/15m/1h)操作建议观望。当前5m/15m与1h趋势方向矛盾市场处于震荡整理状态缺乏清晰的日内交易机会。可关注价格对1h支撑$91,637和压力$92,273的突破情况等待小周期形成共振后再考虑入场。",
"medium_term": "中期(4h/1d)趋势向下但当前价格处于4h关键压力位且与短期上涨动能背离。无明确的中期波段入场点建议观望。可关注价格能否站稳$89,177上方以挑战日线压力$93,080或回落至$86,200-$86,800支撑区域寻找企稳信号。", "medium_term": "中期(4h/1d)操作建议观望。4h看涨与1d看跌形成强烈分歧市场方向不明。建议等待价格有效突破4h压力$93,080确认中期转强或跌破4h支撑$90,612确认中期转弱并结合成交量放大信号再寻找波段交易机会。",
"long_term": "长期(1d/1w)趋势矛盾,日线下跌与周线上涨形成拉锯。周线支撑$88,909已被短暂跌破长期方向待定。建议长期投资者保持观望等待日线趋势当前下跌与周线趋势当前上涨出现明确一致信号后再做布局或利用ambush点位分批建仓。" "long_term": "长期(1d/1w)操作建议:观望。日线与周线趋势不一致,长期趋势未明朗。可关注周线支撑$91,130的防守情况。若价格能站稳该支撑并推动日线趋势转涨形成大周期共振则可能开启长期上涨趋势反之若跌破则长期趋势可能转弱。目前宜耐心等待更明确的趋势信号。"
}, },
"levels": { "levels": {
"current_price": 89158.5, "current_price": 92028.4,
"entry": 89158.5, "entry": 92028.4,
"stop_loss": 88800.0, "stop_loss": 0,
"take_profit_1": 91592.0, "take_profit_1": 0,
"take_profit_2": 91592.0, "take_profit_2": 0,
"take_profit_3": 91592.0 "take_profit_3": 0
}, },
"risk_level": "HIGH", "risk_level": "MEDIUM",
"key_factors": [ "key_factors": [
"多周期趋势严重分歧", "多周期趋势严重分歧,方向不明",
"短期RSI超买与中期下跌趋势冲突", "成交量普遍萎缩,市场动能不足",
"价格处于4小时关键压力位$89,177", "价格位于关键支撑与压力区间内震荡",
"成交量在短期放量但日线缩量", "大周期日线、周线MACD信号矛盾",
"周线长期趋势方向待定" "市场等待突破以选择后续方向"
], ],
"raw_response": "```json\n{\n \"signal\": \"HOLD\",\n \"confidence\": 0.6,\n \"opportunities\": {\n \"short_term_5m_15m_1h\": {\n \"exists\": true,\n \"timeframe_label\": \"短期 (5m/15m/1h)\",\n \"direction\": \"LONG\",\n \"entry_price\": 89158.5,\n \"stop_loss\": 88800.0,\n \"take_profit\": 91592.0,\n \"reasoning\": \"5m和15m周期呈现强劲上涨趋势量化评分28.4/40.9MACD金叉成交量放大但RSI均超买>80。1h周期趋势下跌但MACD金叉扩大价格接近1h压力位$91,592。短期存在基于小周期动量延续的做多机会但需警惕超买回调风险。\",\n \"持仓时间\": \"几分钟到几小时\"\n },\n \"medium_term_4h_1d\": {\n \"exists\": false,\n \"timeframe_label\": \"中期 (4h/1d)\",\n \"direction\": null,\n \"entry_price\": null,\n \"stop_loss\": null,\n \"take_profit\": null,\n \"reasoning\": \"4h和1d周期均显示强劲下跌趋势量化评分-33.4/-23.4与短期上涨趋势形成严重分歧。4h压力位$89,177与当前价格$89,158.5几乎重合构成关键阻力。日线MACD虽金叉但趋势向下RSI中性偏弱缺乏明确的中期反转或延续信号建议观望。\",\n \"持仓时间\": \"数天到一周\"\n },\n \"long_term_1d_1w\": {\n \"exists\": false,\n \"timeframe_label\": \"长期 (1d/1w)\",\n \"direction\": null,\n \"entry_price\": null,\n \"stop_loss\": null,\n \"take_profit\": null,\n \"reasoning\": \"日线下跌趋势与周线上涨趋势方向严重冲突。周线量化评分仅4.3信号模糊MACD死叉扩大RSI弱势。日线趋势向下但MACD金叉显示长期趋势不明朗处于关键抉择期。无明确的长期趋势交易机会需等待日线与周线趋势共振。\",\n \"持仓时间\": \"数周到数月\"\n },\n \"ambush\": {\n \"exists\": true,\n \"price_level\": 86207.0,\n \"reasoning\": \"等待价格回调至1h关键支撑位$86,207附近。该位置接近4h支撑$86,261若价格能在此企稳并出现1h或4h周期的反弹信号如RSI从超卖区回升、MACD金叉可考虑作为中期做多埋伏点博弈日线下跌趋势中的反弹或反转。\",\n \"timeframe\": \"基于1小时和4小时级别的关键支撑位\"\n }\n },\n \"recommendations_by_timeframe\": {\n \"short_term\": \"短期(5m/15m/1h)存在基于小周期动量的日内做多机会但RSI已严重超买风险较高。建议轻仓快进快出严格设置止损于$88,800基于5m ATR目标看向1h压力位$91,592。若价格无法有效突破当前4h压力$89,177应果断离场。\",\n \"medium_term\": \"中期(4h/1d)趋势向下但当前价格处于4h关键压力位且与短期上涨动能背离。无明确的中期波段入场点建议观望。可关注价格能否站稳$89,177上方以挑战日线压力$93,080或回落至$86,200-$86,800支撑区域寻找企稳信号。\",\n \"long_term\": \"长期(1d/1w)趋势矛盾,日线下跌与周线上涨形成拉锯。周线支撑$88,909已被短暂跌破长期方向待定。建议长期投资者保持观望等待日线趋势当前下跌与周线趋势当前上涨出现明确一致信号后再做布局或利用ambush点位分批建仓。\"\n },\n \"reasoning\": \"多周期分析显示市场处于严重分歧状态短期5m/15m强劲看涨中期4h/1d明确看跌长期1d/1w方向矛盾。这种分歧导致整体信号为HOLD。短期上涨面临中期趋势阻力和超买技术指标压制上行空间可能受限。交易机会仅限于快进快出的日内多头中长线需等待趋势共振。\",\n \"risk_level\": \"HIGH\",\n \"key_factors\": [\"多周期趋势严重分歧\", \"短期RSI超买与中期下跌趋势冲突\", \"价格处于4小时关键压力位$89,177\", \"成交量在短期放量但日线缩量\", \"周线长期趋势方向待定\"]\n}\n```", "raw_response": "```json\n{\n \"signal\": \"HOLD\",\n \"confidence\": 0.67,\n \"opportunities\": {\n \"short_term_5m_15m_1h\": {\n \"exists\": false,\n \"timeframe_label\": \"短期 (5m/15m/1h)\",\n \"direction\": null,\n \"entry_price\": null,\n \"stop_loss\": null,\n \"take_profit\": null,\n \"reasoning\": \"短期周期趋势分歧。5m和15m显示下跌趋势量化评分-24.3但1h显示上涨趋势量化评分23.4。动量指标MACD死叉与部分趋势信号矛盾RSI处于中性区域成交量萎缩缺乏明确的共振入场信号。价格在1h支撑$91,637和压力$92,273之间震荡方向不明。\",\n \"持仓时间\": \"几分钟到几小时\"\n },\n \"medium_term_4h_1d\": {\n \"exists\": false,\n \"timeframe_label\": \"中期 (4h/1d)\",\n \"direction\": null,\n \"entry_price\": null,\n \"stop_loss\": null,\n \"take_profit\": null,\n \"reasoning\": \"中期周期趋势严重分歧。4h周期显示上涨趋势量化评分29.3趋势强度moderateRSI 60.2强势但1d周期显示下跌趋势量化评分-23.4趋势强度strong。MACD信号不一致4h金叉收窄1d金叉扩大价格接近4h压力位$93,080但未突破。成交量萎缩市场缺乏明确的波段方向动能建议观望等待趋势统一。\",\n \"持仓时间\": \"数天到一周\"\n },\n \"long_term_1d_1w\": {\n \"exists\": false,\n \"timeframe_label\": \"长期 (1d/1w)\",\n \"direction\": null,\n \"entry_price\": null,\n \"stop_loss\": null,\n \"take_profit\": null,\n \"reasoning\": \"长期周期趋势存在分歧。1d周期显示下跌趋势趋势强度strong而1w周期显示上涨趋势趋势强度moderate。量化评分方向不一致1d: -23.4, 1w: 11.8。周线MACD仍为死叉尽管收窄日线MACD为金叉信号矛盾。价格位于周线支撑$91,130上方但未形成明确的大周期共振趋势缺乏长期布局的清晰入场点。\",\n \"持仓时间\": \"数周到数月\"\n },\n \"ambush\": {\n \"exists\": true,\n \"price_level\": 91130.0,\n \"reasoning\": \"基于周线关键支撑位$91,130设置埋伏。若价格回调至此位置并伴随1h或4h周期出现明确的反弹反转信号如RSI超卖反弹、MACD金叉、放量可考虑分批布局多单博弈周线级别上涨趋势的延续。\",\n \"timeframe\": \"基于周线(1w)的关键支撑位\"\n }\n },\n \"recommendations_by_timeframe\": {\n \"short_term\": \"短期(5m/15m/1h)操作建议观望。当前5m/15m与1h趋势方向矛盾市场处于震荡整理状态缺乏清晰的日内交易机会。可关注价格对1h支撑$91,637和压力$92,273的突破情况等待小周期形成共振后再考虑入场。\",\n \"medium_term\": \"中期(4h/1d)操作建议观望。4h看涨与1d看跌形成强烈分歧市场方向不明。建议等待价格有效突破4h压力$93,080确认中期转强或跌破4h支撑$90,612确认中期转弱并结合成交量放大信号再寻找波段交易机会。\",\n \"long_term\": \"长期(1d/1w)操作建议:观望。日线与周线趋势不一致,长期趋势未明朗。可关注周线支撑$91,130的防守情况。若价格能站稳该支撑并推动日线趋势转涨形成大周期共振则可能开启长期上涨趋势反之若跌破则长期趋势可能转弱。目前宜耐心等待更明确的趋势信号。\"\n },\n \"reasoning\": \"多周期综合分析显示市场处于关键分歧点。短期1h与超短期5m/15m趋势不一致中期4h与1d趋势完全相反长期1d与1w趋势也存在矛盾。各周期未能形成共振市场缺乏统一方向呈现震荡格局。当前价格位于多个周期的关键位之间方向选择有待确认。\",\n \"risk_level\": \"MEDIUM\",\n \"key_factors\": [\"多周期趋势严重分歧,方向不明\", \"成交量普遍萎缩,市场动能不足\", \"价格位于关键支撑与压力区间内震荡\", \"大周期日线、周线MACD信号矛盾\", \"市场等待突破以选择后续方向\"]\n}\n```",
"risk_reward_ratio": 6.79 "risk_reward_ratio": 0
} }
} }

View File

@ -8,6 +8,8 @@ from typing import Dict, Any, Optional
from datetime import datetime from datetime import datetime
import os import os
from config.settings import settings
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -139,241 +141,189 @@ class LLMDecisionMaker:
# Extract context elements # Extract context elements
market_state = market_context.get('market_state', {}) market_state = market_context.get('market_state', {})
key_prices = market_context.get('key_prices', {})
momentum = market_context.get('momentum', {}) momentum = market_context.get('momentum', {})
signal_consensus = market_context.get('signal_consensus', 0.5) signal_consensus = market_context.get('signal_consensus', 0.5)
current_price = market_context.get('current_price', 0) current_price = market_context.get('current_price', 0)
kline_data = market_context.get('kline_data', {})
# Build structured prompt # Build structured prompt
prompt = f"""你是一个专业的加密货币交易分析师。基于以下多时间周期市场分析数据,提供分层次的交易建议。 prompt = f"""你是一个专业的加密货币交易分析师。基于以下多时间周期的K线数据和技术指标,提供分层次的交易建议。
**重要**: 你需要自己从K线数据中识别支撑位和压力位,不要依赖预先计算的值
## 当前价格 ## 当前价格
${current_price:,.2f} ${current_price:,.2f}
## 你的分析任务
1. **分析K线数据** - 识别各周期的支撑位压力位趋势结构
2. **结合技术指标** - RSIMACD成交量等确认信号
3. **给出交易建议** - 分短期/中期/长期三个级别
## 请提供以下内容 (使用JSON格式): ## 请提供以下内容 (使用JSON格式):
{{ {{
"signal": "BUY" | "SELL" | "HOLD", "signal": "BUY" | "SELL" | "HOLD",
"confidence": 0.0-1.0, "confidence": 0.0-1.0,
// 你识别的关键价位
"key_levels": {{
"short_term": {{
"support": [支撑位数组],
"resistance": [压力位数组]
}},
"medium_term": {{
"support": [支撑位数组],
"resistance": [压力位数组]
}},
"long_term": {{
"support": [支撑位数组],
"resistance": [压力位数组]
}}
}},
// 分时间级别的交易机会分析 // 分时间级别的交易机会分析
"opportunities": {{ "opportunities": {{
"short_term_5m_15m_1h": {{ "short_term_5m_15m_1h": {{
"exists": true/false, "exists": true/false,
"timeframe_label": "短期 (5m/15m/1h)",
"direction": "LONG" | "SHORT" | null, "direction": "LONG" | "SHORT" | null,
"entry_price": 进场价格数值或null, "entry_price": 进场价格数值或null,
"stop_loss": 止损价格数值或null, "stop_loss": 止损价格数值或null,
"take_profit": 止盈价格数值或null, "take_profit": 止盈价格数值或null,
"reasoning": "短期日内机会说明", "reasoning": "短期日内机会说明"
"持仓时间": "几分钟到几小时"
}}, }},
"medium_term_4h_1d": {{ "medium_term_4h_1d": {{
"exists": true/false, "exists": true/false,
"timeframe_label": "中期 (4h/1d)",
"direction": "LONG" | "SHORT" | null, "direction": "LONG" | "SHORT" | null,
"entry_price": 进场价格数值或null, "entry_price": 进场价格数值或null,
"stop_loss": 止损价格数值或null, "stop_loss": 止损价格数值或null,
"take_profit": 止盈价格数值或null, "take_profit": 止盈价格数值或null,
"reasoning": "中期波段机会说明", "reasoning": "中期波段机会说明"
"持仓时间": "数天到一周"
}}, }},
"long_term_1d_1w": {{ "long_term_1d_1w": {{
"exists": true/false, "exists": true/false,
"timeframe_label": "长期 (1d/1w)",
"direction": "LONG" | "SHORT" | null, "direction": "LONG" | "SHORT" | null,
"entry_price": 进场价格数值或null, "entry_price": 进场价格数值或null,
"stop_loss": 止损价格数值或null, "stop_loss": 止损价格数值或null,
"take_profit": 止盈价格数值或null, "take_profit": 止盈价格数值或null,
"reasoning": "长期趋势机会说明", "reasoning": "长期趋势机会说明"
"持仓时间": "数周到数月"
}}, }},
"ambush": {{ "ambush": {{
"exists": true/false, "exists": true/false,
"price_level": 埋伏价格数值或null, "price_level": 埋伏价格数值或null,
"reasoning": "埋伏点位说明 (等待回调/反弹到关键位)", "reasoning": "埋伏点位说明"
"timeframe": "基于哪个时间级别的关键位"
}} }}
}}, }},
// 分级别操作建议必填即使某级别无机会也要说明原因 // 分级别操作建议必填
"recommendations_by_timeframe": {{ "recommendations_by_timeframe": {{
"short_term": "短期(5m/15m/1h)操作建议", "short_term": "短期(5m/15m/1h)操作建议",
"medium_term": "中期(4h/1d)操作建议", "medium_term": "中期(4h/1d)操作建议",
"long_term": "长期(1d/1w)操作建议" "long_term": "长期(1d/1w)操作建议"
}}, }},
// 综合分析 "reasoning": "多周期综合分析",
"reasoning": "多周期综合分析 (3-5句话说明各周期是否一致)",
"risk_level": "LOW" | "MEDIUM" | "HIGH", "risk_level": "LOW" | "MEDIUM" | "HIGH",
"key_factors": ["影响因素1", "影响因素2", ...] "key_factors": ["影响因素1", "影响因素2", ...]
}} }}
**输出说明**:
1. **signal**: 主要交易信号 (BUY/SELL/HOLD)
2. **confidence**: 对主要信号的信心度 (0-1)
3. **opportunities**: 分时间级别详细分析
- **short_term_5m_15m_1h**: 短期日内交易机会 (持仓几分钟到几小时)
- 基于5m/15m/1h周期共振
- 止损: 5m/15m ATR × 1.5, 通常0.3%-0.5%
- 止盈: 1h压力/支撑位, 风险回报比1:2
- **medium_term_4h_1d**: 中期波段交易机会 (持仓数天到一周)
- 基于4h/1d周期趋势
- 止损: 4h ATR × 1.5, 通常1%-2%
- 止盈: 日线关键位, 风险回报比1:2.5
- **long_term_1d_1w**: 长期趋势交易机会 (持仓数周到数月)
- 基于1d/1w周期趋势
- 止损: 日线ATR × 1.5, 通常2%-4%
- 止盈: 周线关键位, 风险回报比1:3
- **ambush**: 埋伏点位机会
- 基于日线/周线关键支撑压力位
- 等待价格到达后再决定入场
4. **recommendations_by_timeframe**: 各级别操作建议必填
- 即使某级别无明确机会,也要说明原因和观望理由
5. **reasoning**: 多周期综合分析,说明各周期是否一致,存在哪些分歧
**重要原则**: **重要原则**:
1. **平等对待所有时间级别** - 不要偏向任何周期,根据量化评分客观分析 1. **优先日内短线** - 重点关注 short_term_5m_15m_1h 的日内交易机会
2. **可以同时存在多级别机会** - 例如: 短期做多(日内) + 中期观望 + 长期做空(趋势) 2. **盈利空间1%** - 只有预期盈利 1% 时才给出操作建议否则 exists=false
3. **各级别独立分析** - 短期中期长期分别给出建议,不要混淆 3. **自行识别支撑压力位** - 从K线数据中找出重要的高低点作为支撑压力位
4. **必须填写recommendations_by_timeframe** - 即使是HOLD也要说明理由 4. **响应必须是有效的JSON格式** - 不要包含注释
5. **止损止盈必须匹配时间级别** - 短期用小止损,长期用大止损
6. **响应必须是有效的JSON格式** - 不要包含注释
""" """
# Add comprehensive multi-timeframe analysis if available # Add multi-timeframe technical indicators
if 'multi_timeframe' in market_context: if 'multi_timeframe' in market_context:
mtf = market_context['multi_timeframe'] mtf = market_context['multi_timeframe']
prompt += f"\n## 多时间框架技术分析 (完整指标)\n\n" prompt += "\n## 各周期技术指标\n\n"
# Define timeframe order and display names
tf_order = [ tf_order = [
('5m', '5分钟'), ('5m', '5分钟', '日内短线参考'),
('15m', '15分钟'), ('15m', '15分钟', '日内短线参考'),
('1h', '1小时'), ('1h', '1小时', '短期趋势'),
('4h', '4小时'), ('4h', '4小时', '中期趋势'),
('1d', '日线'), ('1d', '日线', '大趋势'),
('1w', '周线') ('1w', '周线', '长期趋势')
] ]
for tf_key, tf_name in tf_order: for tf_key, tf_name, tf_desc in tf_order:
if tf_key not in mtf: if tf_key not in mtf:
continue continue
data = mtf[tf_key] data = mtf[tf_key]
quant = data.get('quantitative', {}) quant = data.get('quantitative', {})
prompt += f"### {tf_name}周期 ({tf_key})\n" prompt += f"### {tf_name} ({tf_desc})\n"
prompt += f"- 量化评分: {quant.get('composite_score', 0):.1f} | 信号: {quant.get('signal_type', 'HOLD')}\n"
# ===== NEW: 量化评分优先展示 ===== prompt += f"- 趋势: {data.get('trend_direction', '未知')} ({data.get('trend_strength', 'weak')})\n"
prompt += f"**量化评分**: {quant.get('composite_score', 0):.1f} (信号: {quant.get('signal_type', 'HOLD')}, 置信度: {quant.get('confidence', 0):.0%})\n"
prompt += f"- 趋势得分: {quant.get('trend_score', 0):.1f} | 动量得分: {quant.get('momentum_score', 0):.1f} | 订单流: {quant.get('orderflow_score', 0):.1f}\n"
# 原有技术指标
prompt += f"- 趋势: {data.get('trend_direction', '未知')} (强度: {data.get('trend_strength', 'weak')})\n"
prompt += f"- RSI: {data.get('rsi', 50):.1f} ({data.get('rsi_status', '中性')})\n" prompt += f"- RSI: {data.get('rsi', 50):.1f} ({data.get('rsi_status', '中性')})\n"
prompt += f"- MACD: {data.get('macd_signal', '未知')} (柱状图: {data.get('macd_hist', 0):.2f})\n" prompt += f"- MACD: {data.get('macd_signal', '未知')}\n"
prompt += f"- ATR: ${data.get('atr', 0):.2f} ({data.get('atr_pct', 0):.2f}%)\n"
# Support/Resistance
support = data.get('support')
resistance = data.get('resistance')
support_str = f"${support:,.0f}" if support else ""
resistance_str = f"${resistance:,.0f}" if resistance else ""
prompt += f"- 支撑位: {support_str} | 压力位: {resistance_str}\n"
# Volatility
atr = data.get('atr', 0)
atr_pct = data.get('atr_pct', 0)
prompt += f"- 波动率: ATR ${atr:.2f} ({atr_pct:.2f}%)\n"
# Volume
vol_ratio = data.get('volume_ratio', 1) vol_ratio = data.get('volume_ratio', 1)
vol_status = "放量" if vol_ratio > 1.2 else "缩量" if vol_ratio < 0.8 else "正常" vol_status = "放量" if vol_ratio > 1.2 else "缩量" if vol_ratio < 0.8 else "正常"
prompt += f"- 成交量: {vol_status} (比率: {vol_ratio:.2f}x)\n" prompt += f"- 成交量: {vol_status} ({vol_ratio:.2f}x)\n\n"
prompt += "\n"
# Add cross-timeframe analysis insights # Add K-line data
prompt += "### 多周期分析方法\n\n" if kline_data:
prompt += "\n## K线数据 (请从中识别支撑位和压力位)\n\n"
prompt += "格式: t=时间, o=开盘, h=最高, l=最低, c=收盘, v=成交量\n\n"
prompt += "#### 📊 分时间级别交易框架\n\n" tf_kline_order = [
('5m', '5分钟K线 (最近1天)'),
('15m', '15分钟K线 (最近1天)'),
('1h', '1小时K线 (最近3天)'),
('4h', '4小时K线 (最近3天)'),
('1d', '日线K线 (最近30天)'),
('1w', '周线K线 (最近60周)')
]
prompt += "**1⃣ 短期交易 (short_term_5m_15m_1h)** - 持仓: 几分钟到几小时\n\n" for tf_key, tf_desc in tf_kline_order:
prompt += "判断标准:\n" if tf_key not in kline_data:
prompt += "- ✅ **短周期共振**: 5m/15m/1h趋势方向一致\n" continue
prompt += "- ✅ **动量确认**: 5m MACD金叉/死叉 + 15m MACD同向\n"
prompt += "- ✅ **RSI信号**: 5m/15m RSI从超卖(<30)反弹或超买(>70)回落\n"
prompt += "- ✅ **价格位置**: 触及1h或4h支撑/压力位后反弹\n"
prompt += "- ⚠️ **大趋势**: 日线/周线至少不强烈相反\n"
prompt += "- ✅ **成交量**: 5m/15m放量确认突破/反转\n\n"
prompt += "入场条件:\n"
prompt += "- 做多: 5m/15m/1h上涨 + 5m金叉 + 价格>1h支撑 + 放量\n"
prompt += "- 做空: 5m/15m/1h下跌 + 5m死叉 + 价格<1h压力 + 放量\n\n"
prompt += "止盈止损:\n"
prompt += "- 止损: 5m ATR × 1.5 或15m最近低/高点, 约0.3%-0.5%\n"
prompt += "- 止盈: 1h压力/支撑位, 风险回报比≥1:2\n"
prompt += "- 策略: 快进快出, 达成50%目标后移动止损到成本\n\n"
prompt += "**2⃣ 中期交易 (medium_term_4h_1d)** - 持仓: 数天到一周\n\n" klines = kline_data[tf_key]
prompt += "判断标准:\n" if not klines:
prompt += "- ✅ **中周期趋势**: 4h/1d方向一致且趋势明显\n" continue
prompt += "- ✅ **量化评分**: 4h和1d的量化综合得分方向一致\n"
prompt += "- ✅ **MACD共振**: 日线金叉/死叉 + 周线趋势确认\n"
prompt += "- ✅ **关键位突破**: 突破或回踩日线/周线支撑压力位\n"
prompt += "- ✅ **RSI位置**: 日线RSI从超卖(<30)反转或超买(>70)回落\n"
prompt += "- ✅ **入场时机**: 4h/1h回调到位,提供更好入场点\n"
prompt += "- ✅ **成交量**: 日线放量突破确认趋势\n\n"
prompt += "入场条件:\n"
prompt += "- 做多: 日线+周线上涨 + 日线金叉 + 4h回调到日线支撑 + 1h反弹\n"
prompt += "- 做空: 日线+周线下跌 + 日线死叉 + 4h反弹到日线压力 + 1h回落\n\n"
prompt += "止盈止损:\n"
prompt += "- 止损: 4h ATR × 1.5, 约1%-2%\n"
prompt += "- 止盈: 日线关键位, 风险回报比≥1:2.5\n"
prompt += "- 策略: 波段持仓,关注日线趋势变化\n\n"
prompt += "**3⃣ 长期交易 (long_term_1d_1w)** - 持仓: 数周到数月\n\n" prompt += f"### {tf_desc}\n"
prompt += "判断标准:\n" prompt += "```\n"
prompt += "- ✅ **大周期趋势**: 1d/1w方向一致且强劲(strong/moderate)\n"
prompt += "- ✅ **量化评分**: 日线和周线的量化综合得分方向一致且分值高\n"
prompt += "- ✅ **周线MACD**: 周线金叉/死叉确认趋势\n"
prompt += "- ✅ **关键位突破**: 突破周线/月线级别支撑压力位\n"
prompt += "- ✅ **趋势确认**: 多个大周期指标共振,形成明确趋势\n\n"
prompt += "入场条件:\n"
prompt += "- 做多: 日线+周线上涨 + 周线金叉 + 日线回调到周线支撑 + 4h反弹\n"
prompt += "- 做空: 日线+周线下跌 + 周线死叉 + 日线反弹到周线压力 + 4h回落\n\n"
prompt += "止盈止损:\n"
prompt += "- 止损: 日线ATR × 1.5, 约2%-4%\n"
prompt += "- 止盈: 周线压力/支撑位, 风险回报比≥1:3\n"
prompt += "- 策略: 长期持仓,趋势不破不出,移动止损锁定利润\n\n"
prompt += "**4⃣ 埋伏点位 (ambush)** - 提前布局等待机会\n\n" # 对于短周期显示所有K线对于长周期可能只显示最近的一部分
prompt += "适用场景:\n" display_klines = klines
prompt += "- 📌 **当前位置不佳**: 价格处于中间位置,没有好的入场点\n" for k in display_klines:
prompt += "- 📌 **关键位等待**: 有明确的日线/周线支撑压力位可等待\n" prompt += f"{k['t']} | o:{k['o']} h:{k['h']} l:{k['l']} c:{k['c']} v:{k['v']:.0f}\n"
prompt += "- 📌 **趋势延续**: 大周期趋势明确,等待回调/反弹入场\n"
prompt += "- 📌 **反转布局**: 价格接近关键转折点,等待突破确认\n\n"
prompt += "埋伏位置示例:\n"
prompt += "- 做多埋伏: 等待回调到周线/日线支撑位 (例: 价格90500,埋伏88900)\n"
prompt += "- 做空埋伏: 等待反弹到周线/日线压力位 (例: 价格90500,埋伏93000)\n"
prompt += "- 突破埋伏: 等待突破关键位后回踩 (例: 突破91000后回踩90800)\n\n"
prompt += "埋伏策略:\n"
prompt += "- 基于: 日线/周线的关键支撑压力位\n"
prompt += "- 触发: 价格到达埋伏位 + 短周期(1h/4h)出现反转信号\n"
prompt += "- 止损: 埋伏位下方/上方1-2个ATR\n"
prompt += "- 止盈: 下一个日线/周线关键位\n\n"
prompt += "**5⃣ 观望情况** - recommendations_by_timeframe中标注\n" prompt += "```\n\n"
prompt += "- ❌ 某周期趋势不明确或震荡\n"
prompt += "- ❌ 量化评分接近0 (无明确方向)\n"
prompt += "- ❌ 多个周期趋势严重分歧\n"
prompt += "- ❌ 成交量萎缩,市场缺乏动能\n"
prompt += "- ❌ 价格在关键位之间震荡\n\n"
prompt += "#### 🎯 关键分析要点\n" # Add analysis guidelines
prompt += "1. **平等对待各周期** - 周线、日线、小时级别都重要,根据持仓时间选择\n" prompt += """
prompt += "2. **利用量化评分** - 每个周期都有量化综合得分,优先参考这个数值\n" ## 支撑压力位识别方法
prompt += "3. **分级别独立分析** - 短期、中期、长期可以有不同甚至相反的建议\n"
prompt += "4. **趋势共振**: 同级别内多周期一致时,信号最强\n" 1. **短期支撑压力 (5m/15m/1h)**
prompt += "5. **分歧利用**: 短期看多+长期看空 = 日内做多但不持仓过夜\n" - 近1天内的明显高低点
prompt += "6. **必须填写所有级别建议** - recommendations_by_timeframe三个字段都要填\n\n" - 多次触及但未突破的价格
- 整数关口 ( 91000, 92000)
2. **中期支撑压力 (4h/1d)**
- 近几天的重要高低点
- 趋势线位置
- 前期成交密集区
3. **长期支撑压力 (1d/1w)**
- 周线/月线级别的高低点
- 历史重要价格区间
- 大周期趋势线
## 止盈止损设置
- 短期: 止损 0.3%-0.5%, 止盈 1%
- 中期: 止损 1%-2%, 止盈 2%
- 长期: 止损 2%-4%, 止盈 4%
只有当 (take_profit - entry) / entry 1% 时才给出具体建议!
"""
return prompt return prompt
@ -454,6 +404,28 @@ ${current_price:,.2f}
except (ValueError, TypeError): except (ValueError, TypeError):
return default return default
# Helper function to calculate profit percentage
def calc_profit_pct(entry, take_profit, direction):
"""Calculate profit percentage for a trade"""
if not entry or not take_profit or entry <= 0:
return 0
if direction == 'LONG':
return (take_profit - entry) / entry * 100
elif direction == 'SHORT':
return (entry - take_profit) / entry * 100
return 0
# Helper function to check if opportunity meets minimum profit threshold
def meets_profit_threshold(opp, min_profit_pct=1.0):
"""Check if opportunity has at least min_profit_pct profit potential"""
if not opp.get('exists'):
return False
entry = safe_float(opp.get('entry_price'), 0)
tp = safe_float(opp.get('take_profit'), 0)
direction = opp.get('direction')
profit_pct = calc_profit_pct(entry, tp, direction)
return profit_pct >= min_profit_pct
# Parse opportunities structure (support both old and new format) # Parse opportunities structure (support both old and new format)
opportunities = llm_decision.get('opportunities', {}) opportunities = llm_decision.get('opportunities', {})
@ -472,7 +444,43 @@ ${current_price:,.2f}
medium_term = swing medium_term = swing
long_term = {} long_term = {}
# Determine primary levels (priority: short > medium > long) # Apply minimum profit filter to all opportunities
MIN_PROFIT_PCT = settings.MIN_PROFIT_PCT
# Filter short_term
short_term_valid = meets_profit_threshold(short_term, MIN_PROFIT_PCT)
if short_term.get('exists') and not short_term_valid:
profit_pct = calc_profit_pct(
safe_float(short_term.get('entry_price'), 0),
safe_float(short_term.get('take_profit'), 0),
short_term.get('direction')
)
logger.info(f"短期机会被过滤: 盈利空间 {profit_pct:.2f}% < {MIN_PROFIT_PCT}%")
short_term = {'exists': False, 'reasoning': f'盈利空间不足1% (仅{profit_pct:.2f}%),建议观望'}
# Filter medium_term
medium_term_valid = meets_profit_threshold(medium_term, MIN_PROFIT_PCT)
if medium_term.get('exists') and not medium_term_valid:
profit_pct = calc_profit_pct(
safe_float(medium_term.get('entry_price'), 0),
safe_float(medium_term.get('take_profit'), 0),
medium_term.get('direction')
)
logger.info(f"中期机会被过滤: 盈利空间 {profit_pct:.2f}% < {MIN_PROFIT_PCT}%")
medium_term = {'exists': False, 'reasoning': f'盈利空间不足1% (仅{profit_pct:.2f}%),建议观望'}
# Filter long_term
long_term_valid = meets_profit_threshold(long_term, MIN_PROFIT_PCT)
if long_term.get('exists') and not long_term_valid:
profit_pct = calc_profit_pct(
safe_float(long_term.get('entry_price'), 0),
safe_float(long_term.get('take_profit'), 0),
long_term.get('direction')
)
logger.info(f"长期机会被过滤: 盈利空间 {profit_pct:.2f}% < {MIN_PROFIT_PCT}%")
long_term = {'exists': False, 'reasoning': f'盈利空间不足1% (仅{profit_pct:.2f}%),建议观望'}
# Determine primary levels (priority: short > medium > long) - 优先日内短线
entry = market_context.get('current_price', 0) entry = market_context.get('current_price', 0)
stop_loss = 0 stop_loss = 0
take_profit = 0 take_profit = 0

View File

@ -5,6 +5,8 @@ import logging
from typing import Dict, Any, List, Optional from typing import Dict, Any, List, Optional
from datetime import datetime from datetime import datetime
from config.settings import settings
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -71,6 +73,24 @@ class QuantitativeSignalGenerator:
) )
# Build signal # Build signal
# Calculate profit percentage
if signal_type == 'BUY' and entry_level > 0:
profit_pct = (take_profit_levels[0] - entry_level) / entry_level * 100
elif signal_type == 'SELL' and entry_level > 0:
profit_pct = (entry_level - take_profit_levels[0]) / entry_level * 100
else:
profit_pct = 0
# Apply minimum profit filter - 盈利空间不足时建议观望
MIN_PROFIT_PCT = settings.MIN_PROFIT_PCT
original_signal_type = signal_type
filtered_reason = ""
if signal_type != 'HOLD' and profit_pct < MIN_PROFIT_PCT:
logger.info(f"量化信号被过滤: {signal_type} 盈利空间 {profit_pct:.2f}% < {MIN_PROFIT_PCT}%,改为 HOLD")
filtered_reason = f" (原{original_signal_type}信号盈利空间不足{MIN_PROFIT_PCT}%,仅{profit_pct:.2f}%)"
signal_type = 'HOLD'
signal_strength = 0
signal = { signal = {
'timestamp': datetime.now().isoformat(), 'timestamp': datetime.now().isoformat(),
'signal_type': signal_type, # 'BUY', 'SELL', 'HOLD' 'signal_type': signal_type, # 'BUY', 'SELL', 'HOLD'
@ -80,6 +100,7 @@ class QuantitativeSignalGenerator:
trend, momentum, orderflow trend, momentum, orderflow
), ),
'consensus_score': round(consensus_score, 2), # 共识得分 (关键指标) 'consensus_score': round(consensus_score, 2), # 共识得分 (关键指标)
'profit_pct': round(profit_pct, 2), # 预期盈利空间百分比
'scores': { 'scores': {
'trend': round(trend_score, 1), 'trend': round(trend_score, 1),
'momentum': round(momentum_score, 1), 'momentum': round(momentum_score, 1),
@ -98,8 +119,8 @@ class QuantitativeSignalGenerator:
entry_level, stop_loss, take_profit_levels[0] entry_level, stop_loss, take_profit_levels[0]
), ),
'reasoning': QuantitativeSignalGenerator._generate_reasoning( 'reasoning': QuantitativeSignalGenerator._generate_reasoning(
signal_type, trend, momentum, orderflow, breakout original_signal_type, trend, momentum, orderflow, breakout
), ) + filtered_reason,
} }
logger.info( logger.info(