a
This commit is contained in:
parent
236918329e
commit
098132bda6
|
|
@ -261,6 +261,137 @@
|
|||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 推荐分类和风险标签 */
|
||||
.recommendation-tags {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.category-tag,
|
||||
.risk-tag {
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.category-tag {
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.category-tag.category-逆势反弹高风险 {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
.category-tag.category-震荡区间操作 {
|
||||
background-color: #FF9800;
|
||||
}
|
||||
|
||||
.risk-tag {
|
||||
background-color: #9E9E9E;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.risk-tag.risk-高 {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
.risk-tag.risk-中高 {
|
||||
background-color: #FF5722;
|
||||
}
|
||||
|
||||
.risk-tag.risk-中等 {
|
||||
background-color: #FF9800;
|
||||
}
|
||||
|
||||
.risk-tag.risk-低中 {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
/* 用户指南 */
|
||||
.user-guide {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.user-guide strong {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.user-guide-content {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.8;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* 交易教程 */
|
||||
.trading-tutorial {
|
||||
background-color: #fff3cd;
|
||||
border-left: 4px solid #ffc107;
|
||||
padding: 12px 15px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.trading-tutorial strong {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.trading-tutorial p {
|
||||
margin: 0;
|
||||
color: #856404;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 预期持仓时间和退出提醒 */
|
||||
.expected-hold-time,
|
||||
.max-hold-warning {
|
||||
background-color: #e3f2fd;
|
||||
border-left: 4px solid #2196F3;
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.expected-hold-time strong,
|
||||
.max-hold-warning strong {
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
.expected-hold-time span,
|
||||
.max-hold-warning span {
|
||||
color: #1976d2;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.max-hold-warning {
|
||||
background-color: #fff3e0;
|
||||
border-left-color: #ff9800;
|
||||
}
|
||||
|
||||
.max-hold-warning strong,
|
||||
.max-hold-warning span {
|
||||
color: #e65100;
|
||||
}
|
||||
|
||||
.suggested-params {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
|
|
|
|||
|
|
@ -317,6 +317,22 @@ function Recommendations() {
|
|||
</div>
|
||||
|
||||
<div className="card-content">
|
||||
{/* 推荐分类和风险等级标签 */}
|
||||
{(rec.recommendation_category || rec.risk_level) && (
|
||||
<div className="recommendation-tags">
|
||||
{rec.recommendation_category && (
|
||||
<span className={`category-tag category-${rec.recommendation_category?.replace(/[(\(\))]/g, '').replace(/\s+/g, '-').toLowerCase() || 'default'}`}>
|
||||
{rec.recommendation_category}
|
||||
</span>
|
||||
)}
|
||||
{rec.risk_level && (
|
||||
<span className={`risk-tag risk-${rec.risk_level?.replace(/\s+/g, '-').toLowerCase() || 'medium'}`}>
|
||||
风险: {rec.risk_level}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="price-info">
|
||||
<div className="price-item">
|
||||
<label>当前价格:</label>
|
||||
|
|
@ -337,8 +353,24 @@ function Recommendations() {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* 用户指南(人话版计划) */}
|
||||
{rec.user_guide && (
|
||||
<div className="user-guide">
|
||||
<strong>📋 操作计划:</strong>
|
||||
<pre className="user-guide-content">{rec.user_guide}</pre>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 交易教程(如果存在) */}
|
||||
{rec.trading_tutorial && (
|
||||
<div className="trading-tutorial">
|
||||
<strong>💡 交易提示:</strong>
|
||||
<p>{rec.trading_tutorial}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="recommendation-reason">
|
||||
<strong>推荐原因:</strong>
|
||||
<strong>技术分析原因:</strong>
|
||||
<p>{rec.recommendation_reason || '-'}</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -404,6 +436,22 @@ function Recommendations() {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
{/* 预期持仓时间(如果存在) */}
|
||||
{rec.expected_hold_time && (
|
||||
<div className="expected-hold-time">
|
||||
<strong>⏱️ 预期持仓时间:</strong>
|
||||
<span>{rec.expected_hold_time}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 最大持仓天数提醒 */}
|
||||
{rec.max_hold_days && (
|
||||
<div className="max-hold-warning">
|
||||
<strong>⚠️ 退出提醒:</strong>
|
||||
<span>若持仓超过{rec.max_hold_days}天仍未触及第一目标,建议平仓离场重新评估</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showDetails[rec.id || rec.symbol] && (
|
||||
<div className="details-panel">
|
||||
<div className="details-section">
|
||||
|
|
|
|||
|
|
@ -455,6 +455,20 @@ class TradeRecommender:
|
|||
expected_pnl_1 = (estimated_win_rate / 100) * take_profit_1_usdt - ((100 - estimated_win_rate) / 100) * stop_loss_usdt
|
||||
expected_pnl_2 = (estimated_win_rate / 100) * take_profit_2_usdt - ((100 - estimated_win_rate) / 100) * stop_loss_usdt
|
||||
|
||||
# 分类推荐类型和风险等级
|
||||
recommendation_category, risk_level, simple_reason, risk_warning, trading_tutorial = self._classify_recommendation(
|
||||
market_regime, trend_4h, direction, trade_signal, signal_strength
|
||||
)
|
||||
|
||||
# 计算预期持仓时间(基于策略周期和市场状态)
|
||||
expected_hold_time = self._estimate_hold_time(market_regime, trend_4h, direction, signal_strength)
|
||||
|
||||
# 生成用户指南(人话版计划)
|
||||
user_guide = self._generate_user_guide(
|
||||
symbol, direction, suggested_limit_price, stop_loss_price, take_profit_1, take_profit_2,
|
||||
simple_reason, expected_hold_time, risk_warning, recommendation_category
|
||||
)
|
||||
|
||||
# 基础推荐数据
|
||||
base_data = {
|
||||
'symbol': symbol,
|
||||
|
|
@ -488,7 +502,14 @@ class TradeRecommender:
|
|||
'take_profit_1_usdt': round(take_profit_1_usdt, 2),
|
||||
'take_profit_2_usdt': round(take_profit_2_usdt, 2),
|
||||
'recommendation_time': recommendation_time,
|
||||
'timestamp': timestamp
|
||||
'timestamp': timestamp,
|
||||
# 新增字段:用户指南和分类
|
||||
'user_guide': user_guide,
|
||||
'recommendation_category': recommendation_category,
|
||||
'risk_level': risk_level,
|
||||
'expected_hold_time': expected_hold_time,
|
||||
'trading_tutorial': trading_tutorial,
|
||||
'max_hold_days': 3 # 最大持仓天数(超过此天数建议平仓)
|
||||
}
|
||||
|
||||
# 限价单推荐
|
||||
|
|
@ -507,15 +528,159 @@ class TradeRecommender:
|
|||
|
||||
logger.debug(
|
||||
f"✓ 生成推荐: {symbol} {direction} "
|
||||
f"(信号强度: {signal_strength}/10, 胜率预估: {estimated_win_rate:.1f}%)"
|
||||
f"(信号强度: {signal_strength}/10, 胜率预估: {estimated_win_rate:.1f}%, "
|
||||
f"分类: {recommendation_category}, 风险: {risk_level})"
|
||||
)
|
||||
|
||||
return [limit_recommendation, market_recommendation]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"创建推荐失败 {symbol_info.get('symbol', 'unknown')}: {e}")
|
||||
logger.error(f"创建推荐失败 {symbol_info.get('symbol', 'unknown')}: {e}", exc_info=True)
|
||||
return None
|
||||
|
||||
def _classify_recommendation(
|
||||
self,
|
||||
market_regime: str,
|
||||
trend_4h: Optional[str],
|
||||
direction: str,
|
||||
trade_signal: Dict,
|
||||
signal_strength: int
|
||||
) -> tuple:
|
||||
"""
|
||||
分类推荐类型和风险等级
|
||||
|
||||
Returns:
|
||||
(recommendation_category, risk_level, simple_reason, risk_warning, trading_tutorial)
|
||||
"""
|
||||
# 判断是否为逆趋势交易
|
||||
is_counter_trend = False
|
||||
if trend_4h:
|
||||
if (direction == 'BUY' and trend_4h == 'down') or (direction == 'SELL' and trend_4h == 'up'):
|
||||
is_counter_trend = True
|
||||
|
||||
# 分类推荐类型
|
||||
if market_regime == 'trending':
|
||||
if not is_counter_trend:
|
||||
# 顺趋势突破
|
||||
category = "顺趋势突破"
|
||||
risk_level = "中等"
|
||||
simple_reason = "趋势明确,顺势而为,胜率较高"
|
||||
risk_warning = "趋势可能反转,注意止损保护"
|
||||
tutorial = "此类交易适合跟随趋势,持仓时间可稍长,但需关注趋势是否持续"
|
||||
else:
|
||||
# 逆趋势反弹(高风险)
|
||||
category = "逆势反弹(高风险)"
|
||||
risk_level = "高"
|
||||
simple_reason = "逆趋势操作,风险较高,适合快进快出"
|
||||
risk_warning = "⚠️ 高风险:逆趋势交易胜率较低,务必严格止损,快进快出"
|
||||
tutorial = "此类交易胜率较低,仅适合短线快进快出,务必严格止损。建议持仓不超过数小时,一旦触及止损立即离场"
|
||||
elif market_regime == 'ranging':
|
||||
# 震荡区间操作
|
||||
category = "震荡区间操作"
|
||||
risk_level = "中等"
|
||||
simple_reason = "市场震荡,在区间边界操作,适合高抛低吸"
|
||||
risk_warning = "震荡可能转为趋势,注意突破风险"
|
||||
tutorial = "此类交易适合在震荡区间边界操作,预期持仓时间较短(数小时至1天),到达目标及时止盈"
|
||||
else:
|
||||
# 未知市场状态
|
||||
category = "市场状态不明"
|
||||
risk_level = "中高"
|
||||
simple_reason = "市场状态不明确,谨慎操作"
|
||||
risk_warning = "市场状态不明,建议降低仓位或等待更明确信号"
|
||||
tutorial = "市场状态不明确,建议谨慎操作,降低仓位,严格止损"
|
||||
|
||||
# 根据信号强度调整风险等级
|
||||
if signal_strength >= 7:
|
||||
if risk_level == "高":
|
||||
risk_level = "中高"
|
||||
elif risk_level == "中等":
|
||||
risk_level = "低中"
|
||||
elif signal_strength < 5:
|
||||
if risk_level == "中等":
|
||||
risk_level = "中高"
|
||||
elif risk_level == "低中":
|
||||
risk_level = "中等"
|
||||
|
||||
return category, risk_level, simple_reason, risk_warning, tutorial
|
||||
|
||||
def _estimate_hold_time(
|
||||
self,
|
||||
market_regime: str,
|
||||
trend_4h: Optional[str],
|
||||
direction: str,
|
||||
signal_strength: int
|
||||
) -> str:
|
||||
"""
|
||||
估算预期持仓时间
|
||||
|
||||
Returns:
|
||||
预期持仓时间的文字描述
|
||||
"""
|
||||
# 基于策略周期(1H/15min)和市场状态估算
|
||||
if market_regime == 'trending':
|
||||
# 趋势市场,持仓时间可能较长
|
||||
if signal_strength >= 7:
|
||||
return "预期持仓:数小时至2天(趋势明确,可适当延长持仓)"
|
||||
else:
|
||||
return "预期持仓:数小时至1天(趋势较弱,及时止盈)"
|
||||
elif market_regime == 'ranging':
|
||||
# 震荡市场,持仓时间较短
|
||||
return "预期持仓:数小时至半天(震荡市场,快进快出)"
|
||||
else:
|
||||
# 未知状态,保守估计
|
||||
return "预期持仓:数小时(市场状态不明,谨慎持仓)"
|
||||
|
||||
def _generate_user_guide(
|
||||
self,
|
||||
symbol: str,
|
||||
direction: str,
|
||||
limit_price: float,
|
||||
stop_loss: float,
|
||||
tp1: float,
|
||||
tp2: float,
|
||||
simple_reason: str,
|
||||
expected_hold_time: str,
|
||||
risk_warning: str,
|
||||
category: str
|
||||
) -> str:
|
||||
"""
|
||||
生成用户指南(人话版计划)
|
||||
|
||||
Args:
|
||||
symbol: 交易对
|
||||
direction: 方向
|
||||
limit_price: 建议入场价(限价单)
|
||||
stop_loss: 止损价
|
||||
tp1: 第一目标止盈价
|
||||
tp2: 第二目标止盈价
|
||||
simple_reason: 简单原因
|
||||
expected_hold_time: 预期持仓时间
|
||||
risk_warning: 风险警告
|
||||
category: 推荐分类
|
||||
|
||||
Returns:
|
||||
用户指南文本
|
||||
"""
|
||||
direction_cn = "买入" if direction == 'BUY' else "卖出"
|
||||
|
||||
user_guide = f"""【操作计划】{direction_cn} {symbol}
|
||||
【推荐类型】{category}
|
||||
【核心理由】{simple_reason}
|
||||
【具体点位】
|
||||
• 入场价(限价单): {limit_price:.4f} USDT
|
||||
• 止损价: {stop_loss:.4f} USDT
|
||||
• 第一目标: {tp1:.4f} USDT(盈亏比1:1)
|
||||
• 第二目标: {tp2:.4f} USDT(盈亏比2.5:1)
|
||||
【持仓周期】{expected_hold_time}
|
||||
【退出条件】
|
||||
• 触及止损:立即平仓
|
||||
• 触及第一目标:可部分止盈或全部止盈
|
||||
• 触及第二目标:建议全部止盈
|
||||
• 持仓超过3天未触及第一目标:建议平仓离场重新评估
|
||||
【关键提醒】{risk_warning}"""
|
||||
|
||||
return user_guide
|
||||
|
||||
async def get_active_recommendations(self) -> List[Dict]:
|
||||
"""获取当前有效的推荐"""
|
||||
if DB_AVAILABLE and TradeRecommendation:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user