updateupdate
This commit is contained in:
parent
5f11ec2308
commit
1809a45a5b
@ -54,14 +54,6 @@ class CryptoAgent:
|
||||
# 模拟交易服务(始终启用)
|
||||
self.paper_trading = get_paper_trading_service()
|
||||
|
||||
# 实盘交易服务(如果配置了 API)
|
||||
self.real_trading = None
|
||||
try:
|
||||
from app.services.real_trading_service import get_real_trading_service
|
||||
self.real_trading = get_real_trading_service()
|
||||
except Exception as e:
|
||||
logger.warning(f"实盘交易服务初始化失败: {e}")
|
||||
|
||||
# 状态管理
|
||||
self.last_signals: Dict[str, Dict[str, Any]] = {}
|
||||
self.signal_cooldown: Dict[str, datetime] = {}
|
||||
@ -87,13 +79,7 @@ class CryptoAgent:
|
||||
})
|
||||
|
||||
logger.info(f"加密货币智能体初始化完成(LLM 驱动),监控交易对: {self.symbols}")
|
||||
logger.info(f"📊 交易: 始终启用")
|
||||
|
||||
if self.real_trading:
|
||||
auto_status = "启用" if self.real_trading.get_auto_trading_status() else "禁用"
|
||||
logger.info(f"实盘交易: 已配置 (自动交易: {auto_status})")
|
||||
else:
|
||||
logger.info(f"实盘交易: 未配置")
|
||||
logger.info(f"📊 模拟交易: 始终启用")
|
||||
|
||||
def _on_price_update(self, symbol: str, price: float):
|
||||
"""处理实时价格更新(用于模拟交易)"""
|
||||
@ -555,50 +541,27 @@ class CryptoAgent:
|
||||
|
||||
# 获取配置
|
||||
paper_trading_enabled = self.settings.paper_trading_enabled
|
||||
real_trading_enabled = self.settings.real_trading_enabled
|
||||
|
||||
# 分别存储模拟和实盘的决策
|
||||
paper_decision = None
|
||||
real_decision = None
|
||||
|
||||
# 交易决策
|
||||
if paper_trading_enabled:
|
||||
logger.info(f"\n📊 【交易决策】")
|
||||
positions, account, pending_orders = self._get_trading_state(use_real_trading=False)
|
||||
positions, account, pending_orders = self._get_trading_state()
|
||||
# 过滤:只传递当前symbol的挂单给决策器,避免LLM搞混
|
||||
pending_orders_for_symbol = [o for o in pending_orders if o.get('symbol') == symbol]
|
||||
paper_decision = await self.decision_maker.make_decision(
|
||||
decision = await self.decision_maker.make_decision(
|
||||
market_signal, positions, account, current_price, pending_orders_for_symbol
|
||||
)
|
||||
self._log_trading_decision(paper_decision)
|
||||
self._log_trading_decision(decision)
|
||||
# 发送交易决策通知
|
||||
await self._send_trading_decision_notification(paper_decision, market_signal, current_price, is_paper=True)
|
||||
await self._send_trading_decision_notification(decision, market_signal, current_price)
|
||||
else:
|
||||
logger.info(f"⏸️ 交易未启用")
|
||||
|
||||
# 实盘交易决策
|
||||
if real_trading_enabled:
|
||||
logger.info(f"\n💰 【实盘交易决策】")
|
||||
# 检查是否开启自动交易
|
||||
if self.real_trading and self.real_trading.get_auto_trading_status():
|
||||
positions, account, pending_orders = self._get_trading_state(use_real_trading=True)
|
||||
# 过滤:只传递当前symbol的挂单给决策器,避免LLM搞混
|
||||
pending_orders_for_symbol = [o for o in pending_orders if o.get('symbol') == symbol]
|
||||
real_decision = await self.decision_maker.make_decision(
|
||||
market_signal, positions, account, current_price, pending_orders_for_symbol
|
||||
)
|
||||
self._log_trading_decision(real_decision)
|
||||
# 发送交易决策通知
|
||||
await self._send_trading_decision_notification(real_decision, market_signal, current_price, is_paper=False)
|
||||
else:
|
||||
logger.info(f"⏸️ 实盘自动交易未开启")
|
||||
else:
|
||||
logger.info(f"⏸️ 实盘交易未启用")
|
||||
decision = None
|
||||
|
||||
# ============================================================
|
||||
# 第三阶段:执行交易决策
|
||||
# ============================================================
|
||||
await self._execute_decisions(paper_decision, real_decision, market_signal, current_price)
|
||||
await self._execute_decisions(decision, market_signal, current_price)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 分析 {symbol} 出错: {e}")
|
||||
@ -709,24 +672,16 @@ class CryptoAgent:
|
||||
if risk:
|
||||
logger.info(f" 风险: {risk}")
|
||||
|
||||
def _get_trading_state(self, use_real_trading: bool = False) -> tuple:
|
||||
def _get_trading_state(self) -> tuple:
|
||||
"""
|
||||
获取交易状态(持仓和账户)
|
||||
|
||||
Args:
|
||||
use_real_trading: True 获取实盘状态,False 获取模拟交易状态
|
||||
|
||||
Returns:
|
||||
(positions, account, pending_orders) - 持仓列表、账户状态、挂单列表
|
||||
"""
|
||||
if use_real_trading and self.real_trading:
|
||||
# 实盘交易
|
||||
active_orders = self.real_trading.get_active_orders()
|
||||
account = self.real_trading.get_account_status()
|
||||
else:
|
||||
# 模拟交易
|
||||
active_orders = self.paper_trading.get_active_orders()
|
||||
account = self.paper_trading.get_account_status()
|
||||
# 模拟交易
|
||||
active_orders = self.paper_trading.get_active_orders()
|
||||
account = self.paper_trading.get_account_status()
|
||||
|
||||
# 分离持仓和挂单
|
||||
position_list = []
|
||||
@ -756,10 +711,9 @@ class CryptoAgent:
|
||||
|
||||
return position_list, account, pending_orders
|
||||
|
||||
async def _execute_decisions(self, paper_decision: Dict[str, Any],
|
||||
real_decision: Dict[str, Any],
|
||||
async def _execute_decisions(self, decision: Dict[str, Any],
|
||||
market_signal: Dict[str, Any], current_price: float):
|
||||
"""执行交易决策(模拟和实盘分别执行)"""
|
||||
"""执行交易决策"""
|
||||
# 选择最佳信号用于保存
|
||||
best_signal = self._get_best_signal_from_market(market_signal)
|
||||
|
||||
@ -773,20 +727,15 @@ class CryptoAgent:
|
||||
|
||||
# 获取配置
|
||||
paper_trading_enabled = self.settings.paper_trading_enabled
|
||||
real_trading_enabled = self.settings.real_trading_enabled
|
||||
|
||||
# 记录执行结果
|
||||
paper_executed = False
|
||||
real_executed = False
|
||||
|
||||
# ============================================================
|
||||
# 执行交易决策
|
||||
# ============================================================
|
||||
if paper_trading_enabled and paper_decision:
|
||||
decision_type = paper_decision.get('decision', 'HOLD')
|
||||
if paper_trading_enabled and decision:
|
||||
decision_type = decision.get('decision', 'HOLD')
|
||||
|
||||
if decision_type == 'HOLD':
|
||||
reasoning = paper_decision.get('reasoning', '观望')
|
||||
reasoning = decision.get('reasoning', '观望')
|
||||
logger.info(f"\n📊 交易决策: {reasoning}")
|
||||
# HOLD决策的理由已在交易决策通知中说明,无需单独通知
|
||||
else:
|
||||
@ -795,7 +744,7 @@ class CryptoAgent:
|
||||
if decision_type in ['OPEN', 'ADD']:
|
||||
# 先执行交易
|
||||
logger.info(f" 准备执行交易...")
|
||||
result = await self._execute_paper_trade(paper_decision, market_signal, current_price)
|
||||
result = await self._execute_paper_trade(decision, market_signal, current_price)
|
||||
|
||||
# 检查是否成功执行
|
||||
order = result.get('order') if result else None
|
||||
@ -806,8 +755,7 @@ class CryptoAgent:
|
||||
if hasattr(order, 'order_id') and order.order_id:
|
||||
logger.info(f" 订单验证通过: {order.order_id}")
|
||||
# 只有成功创建订单后才发送通知
|
||||
await self._send_signal_notification(market_signal, paper_decision, current_price, is_paper=True)
|
||||
paper_executed = True
|
||||
await self._send_signal_notification(market_signal, decision, current_price)
|
||||
else:
|
||||
logger.error(f" ❌ 订单对象无效: 缺少order_id属性")
|
||||
# 订单创建失败,理由已在日志中记录,无需单独通知
|
||||
@ -816,101 +764,28 @@ class CryptoAgent:
|
||||
reason = result.get('message', '订单创建失败') if result else '订单创建失败'
|
||||
logger.warning(f" ⚠️ 交易未执行: {reason}")
|
||||
elif decision_type == 'CLOSE':
|
||||
close_success = await self._execute_close(paper_decision, current_price, paper_trading=True)
|
||||
close_success = await self._execute_close(decision, current_price)
|
||||
# CLOSE 操作也发送执行通知
|
||||
if close_success:
|
||||
await self._send_signal_notification(market_signal, paper_decision, current_price, is_paper=True)
|
||||
paper_executed = True
|
||||
await self._send_signal_notification(market_signal, decision, current_price)
|
||||
else:
|
||||
logger.warning(f" ⚠️ 平仓未成功执行,跳过通知")
|
||||
elif decision_type == 'CANCEL_PENDING':
|
||||
cancel_success = await self._execute_cancel_pending(paper_decision, paper_trading=True)
|
||||
cancel_success = await self._execute_cancel_pending(decision)
|
||||
# CANCEL_PENDING 操作也发送执行通知
|
||||
if cancel_success:
|
||||
await self._send_signal_notification(market_signal, paper_decision, current_price, is_paper=True)
|
||||
paper_executed = True
|
||||
await self._send_signal_notification(market_signal, decision, current_price)
|
||||
else:
|
||||
logger.warning(f" ⚠️ 取消挂单未成功执行,跳过通知")
|
||||
elif decision_type == 'UPDATE_PENDING':
|
||||
update_success = await self._execute_update_pending(paper_decision, paper_trading=True)
|
||||
# UPDATE_PENDING 操作也发送执行通知
|
||||
if update_success:
|
||||
await self._send_signal_notification(market_signal, paper_decision, current_price, is_paper=True)
|
||||
paper_executed = True
|
||||
else:
|
||||
logger.warning(f" ⚠️ 更新挂单未成功执行,跳过通知")
|
||||
elif decision_type == 'REDUCE':
|
||||
reduce_success = await self._execute_reduce(paper_decision, paper_trading=True)
|
||||
reduce_success = await self._execute_reduce(decision)
|
||||
# REDUCE 操作也发送执行通知
|
||||
if reduce_success:
|
||||
await self._send_signal_notification(market_signal, paper_decision, current_price, is_paper=True)
|
||||
paper_executed = True
|
||||
await self._send_signal_notification(market_signal, decision, current_price)
|
||||
else:
|
||||
logger.warning(f" ⚠️ 减仓未成功执行,跳过通知")
|
||||
|
||||
# ============================================================
|
||||
# 执行实盘交易决策
|
||||
# ============================================================
|
||||
if real_trading_enabled and real_decision:
|
||||
# 检查是否开启自动交易
|
||||
if self.real_trading and self.real_trading.get_auto_trading_status():
|
||||
decision_type = real_decision.get('decision', 'HOLD')
|
||||
|
||||
if decision_type == 'HOLD':
|
||||
reasoning = real_decision.get('reasoning', '观望')
|
||||
logger.info(f"\n💰 实盘交易: {reasoning}")
|
||||
# HOLD决策的理由已在交易决策通知中说明,无需单独通知
|
||||
else:
|
||||
logger.info(f"\n💰 【执行实盘交易】")
|
||||
|
||||
if decision_type in ['OPEN', 'ADD']:
|
||||
# 先执行交易
|
||||
result = await self._execute_real_trade(real_decision, market_signal, current_price)
|
||||
# 检查是否成功执行
|
||||
if result and result.get('success'):
|
||||
# 只有成功创建订单后才发送通知
|
||||
await self._send_signal_notification(market_signal, real_decision, current_price, is_paper=False)
|
||||
real_executed = True
|
||||
else:
|
||||
# 订单创建失败,理由已在日志中记录,无需单独通知
|
||||
reason = result.get('message', '订单创建失败') if result else '订单创建失败'
|
||||
logger.warning(f" ⚠️ 实盘交易未执行: {reason}")
|
||||
elif decision_type == 'CLOSE':
|
||||
close_success = await self._execute_close(real_decision, current_price, paper_trading=False)
|
||||
# CLOSE 操作也发送执行通知
|
||||
if close_success:
|
||||
await self._send_signal_notification(market_signal, real_decision, current_price, is_paper=False)
|
||||
real_executed = True
|
||||
else:
|
||||
logger.warning(f" ⚠️ 实盘平仓未成功执行,跳过通知")
|
||||
elif decision_type == 'CANCEL_PENDING':
|
||||
cancel_success = await self._execute_cancel_pending(real_decision, paper_trading=False)
|
||||
# CANCEL_PENDING 操作也发送执行通知
|
||||
if cancel_success:
|
||||
await self._send_signal_notification(market_signal, real_decision, current_price, is_paper=False)
|
||||
real_executed = True
|
||||
else:
|
||||
logger.warning(f" ⚠️ 实盘取消挂单未成功执行,跳过通知")
|
||||
elif decision_type == 'UPDATE_PENDING':
|
||||
update_success = await self._execute_update_pending(real_decision, paper_trading=False)
|
||||
# UPDATE_PENDING 操作也发送执行通知
|
||||
if update_success:
|
||||
await self._send_signal_notification(market_signal, real_decision, current_price, is_paper=False)
|
||||
real_executed = True
|
||||
else:
|
||||
logger.warning(f" ⚠️ 实盘更新挂单未成功执行,跳过通知")
|
||||
elif decision_type == 'REDUCE':
|
||||
reduce_success = await self._execute_reduce(real_decision, paper_trading=False)
|
||||
# REDUCE 操作也发送执行通知
|
||||
if reduce_success:
|
||||
await self._send_signal_notification(market_signal, real_decision, current_price, is_paper=False)
|
||||
real_executed = True
|
||||
else:
|
||||
logger.warning(f" ⚠️ 实盘减仓未成功执行,跳过通知")
|
||||
|
||||
# 如果都没有执行,给出提示
|
||||
if not paper_executed and not real_executed:
|
||||
logger.info(f"\n⏸️ 所有交易均为观望,无需执行")
|
||||
else:
|
||||
logger.info(f"\n⏸️ 交易未启用或决策为空")
|
||||
|
||||
def _get_best_signal_from_market(self, market_signal: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""从市场信号中获取最佳信号"""
|
||||
@ -1094,15 +969,14 @@ class CryptoAgent:
|
||||
|
||||
async def _send_trading_decision_notification(self, decision: Dict[str, Any],
|
||||
market_signal: Dict[str, Any],
|
||||
current_price: float,
|
||||
is_paper: bool = True):
|
||||
current_price: float):
|
||||
"""发送交易决策通知(第二阶段)"""
|
||||
try:
|
||||
decision_type = decision.get('decision', 'HOLD')
|
||||
symbol = market_signal.get('symbol')
|
||||
|
||||
# 账户类型标识
|
||||
account_type = "📊 交易" if is_paper else "💰 实盘"
|
||||
account_type = "📊 交易"
|
||||
|
||||
# 决策类型映射
|
||||
decision_map = {
|
||||
@ -1228,8 +1102,7 @@ class CryptoAgent:
|
||||
logger.debug(traceback.format_exc())
|
||||
|
||||
async def _send_signal_notification(self, market_signal: Dict[str, Any],
|
||||
decision: Dict[str, Any], current_price: float,
|
||||
is_paper: bool = True):
|
||||
decision: Dict[str, Any], current_price: float):
|
||||
"""发送交易执行通知(第三阶段)"""
|
||||
try:
|
||||
decision_type = decision.get('decision', 'HOLD')
|
||||
@ -1259,7 +1132,7 @@ class CryptoAgent:
|
||||
decision_text = decision_map.get(decision_type, decision_type)
|
||||
|
||||
# 账户类型标识
|
||||
account_type = "📊" if is_paper else "💰"
|
||||
account_type = "📊"
|
||||
|
||||
# 方向图标
|
||||
if 'long' in action.lower() or 'buy' in action.lower():
|
||||
@ -1365,14 +1238,18 @@ class CryptoAgent:
|
||||
action = decision.get('action', '')
|
||||
position_size = decision.get('position_size', 'light')
|
||||
|
||||
# 直接使用 LLM 决策的 quantity
|
||||
quantity = decision.get('quantity', 0)
|
||||
if quantity <= 0:
|
||||
logger.warning(f" ⚠️ LLM 决策的 quantity 无效: {quantity},使用默认值")
|
||||
quantity = self._calculate_quantity_by_position_size(position_size, real_trading=False)
|
||||
# 使用新的动态仓位计算方法
|
||||
logger.info(f" 计算动态仓位: {position_size}")
|
||||
margin, position_value = self.paper_trading._calculate_dynamic_position(position_size, symbol)
|
||||
|
||||
if margin <= 0:
|
||||
logger.warning(f" ⚠️ 计算的保证金无效: {margin},无法开仓")
|
||||
return False
|
||||
|
||||
quantity = margin # 保证金金额
|
||||
|
||||
logger.info(f" 准备创建订单: {symbol} {action} {position_size}")
|
||||
logger.info(f" LLM 决策金额: ${quantity:.2f} USDT")
|
||||
logger.info(f" 保证金: ${quantity:.2f} | 持仓价值: ${position_value:.2f}")
|
||||
|
||||
# 转换决策的 action 为 paper_trading 期望的格式
|
||||
trading_action = self._convert_trading_action(action)
|
||||
@ -1395,7 +1272,7 @@ class CryptoAgent:
|
||||
'confidence': decision.get('confidence', 50),
|
||||
'signal_grade': 'B', # 默认B级
|
||||
'position_size': position_size,
|
||||
'quantity': quantity # 使用 LLM 决策的金额
|
||||
'quantity': quantity # 使用计算后的保证金金额
|
||||
}
|
||||
|
||||
logger.debug(f" 订单数据: {order_data}")
|
||||
@ -1464,66 +1341,12 @@ class CryptoAgent:
|
||||
|
||||
return position_config.get(position_size, 200)
|
||||
|
||||
async def _execute_real_trade(self, decision: Dict[str, Any], market_signal: Dict[str, Any], current_price: float):
|
||||
"""执行实盘交易"""
|
||||
try:
|
||||
symbol = decision.get('symbol')
|
||||
action = decision.get('action', '')
|
||||
position_size = decision.get('position_size', 'light')
|
||||
|
||||
# 直接使用 LLM 决策的 quantity
|
||||
quantity = decision.get('quantity', 0)
|
||||
if quantity <= 0:
|
||||
logger.warning(f" ⚠️ LLM 决策的 quantity 无效: {quantity},使用默认值")
|
||||
quantity = self._calculate_quantity_by_position_size(position_size, real_trading=True)
|
||||
|
||||
logger.info(f" 实盘交易: {position_size} → 保证金 ${quantity:.2f} USDT → 持仓价值 ${quantity * 20:.2f}")
|
||||
|
||||
# 转换决策的 action 为 paper_trading 期望的格式
|
||||
trading_action = self._convert_trading_action(action)
|
||||
|
||||
# 从市场信号中获取入场方式和入场价格
|
||||
best_signal = self._get_best_signal_from_market(market_signal)
|
||||
entry_type = best_signal.get('entry_type', 'market') if best_signal else 'market'
|
||||
entry_price = best_signal.get('entry_price', current_price) if best_signal else current_price
|
||||
|
||||
logger.info(f" 入场方式: {entry_type} | 入场价格: ${entry_price:,.2f}")
|
||||
|
||||
# 转换决策为订单格式(价格字段已在 LLM 解析时转换为 float)
|
||||
order_data = {
|
||||
'symbol': symbol,
|
||||
'action': trading_action, # 使用转换后的 action
|
||||
'entry_type': entry_type, # 使用信号中的入场方式
|
||||
'entry_price': entry_price if entry_type == 'limit' else current_price, # limit单使用entry_price,market单使用current_price
|
||||
'stop_loss': decision.get('stop_loss'),
|
||||
'take_profit': decision.get('take_profit'),
|
||||
'confidence': decision.get('confidence', 50),
|
||||
'signal_grade': 'B',
|
||||
'position_size': position_size,
|
||||
'quantity': quantity # 使用 LLM 决策的金额
|
||||
}
|
||||
|
||||
result = self.real_trading.create_order_from_signal(order_data, current_price)
|
||||
|
||||
if result.get('success'):
|
||||
logger.info(f" 💰 已创建实盘订单: {result.get('order_id')} | 持仓价值: ${quantity * 20:.2f}")
|
||||
await self._notify_real_order_created(symbol, decision, result)
|
||||
else:
|
||||
logger.warning(f" ⚠️ 创建实盘订单失败: {result.get('message', 'Unknown error')}")
|
||||
|
||||
# 返回结果
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"执行实盘交易失败: {e}")
|
||||
|
||||
async def _execute_close(self, decision: Dict[str, Any], current_price: float, paper_trading: bool = True) -> bool:
|
||||
async def _execute_close(self, decision: Dict[str, Any], current_price: float) -> bool:
|
||||
"""执行平仓
|
||||
|
||||
Args:
|
||||
decision: 交易决策(应包含 orders_to_close 字段)
|
||||
current_price: 当前价格
|
||||
paper_trading: True=模拟交易, False=实盘交易
|
||||
|
||||
Returns:
|
||||
是否成功执行平仓
|
||||
@ -1532,71 +1355,59 @@ class CryptoAgent:
|
||||
symbol = decision.get('symbol')
|
||||
orders_to_close = decision.get('orders_to_close', [])
|
||||
|
||||
if paper_trading:
|
||||
# 模拟交易平仓
|
||||
if self.paper_trading:
|
||||
logger.info(f" 🔒 平仓: {symbol}")
|
||||
logger.info(f" 理由: {decision.get('reasoning', '')}")
|
||||
if self.paper_trading:
|
||||
logger.info(f" 🔒 平仓: {symbol}")
|
||||
logger.info(f" 理由: {decision.get('reasoning', '')}")
|
||||
|
||||
# 如果决策中没有指定订单ID,则获取该交易对的所有活跃订单
|
||||
if not orders_to_close:
|
||||
logger.warning(f" ⚠️ 决策中未指定 orders_to_close,将平仓 {symbol} 的所有持仓")
|
||||
active_orders = self.paper_trading.get_active_orders(symbol)
|
||||
orders_to_close = [o.get('order_id') for o in active_orders if o.get('status') in ('OPEN', 'FILLED', 'PENDING')]
|
||||
# 如果决策中没有指定订单ID,则获取该交易对的所有活跃订单
|
||||
if not orders_to_close:
|
||||
logger.warning(f" ⚠️ 决策中未指定 orders_to_close,将平仓 {symbol} 的所有持仓")
|
||||
active_orders = self.paper_trading.get_active_orders(symbol)
|
||||
orders_to_close = [o.get('order_id') for o in active_orders if o.get('status') in ('OPEN', 'FILLED', 'PENDING')]
|
||||
|
||||
if not orders_to_close:
|
||||
logger.warning(f" 没有找到需要平仓的订单")
|
||||
return False
|
||||
if not orders_to_close:
|
||||
logger.warning(f" 没有找到需要平仓的订单")
|
||||
return False
|
||||
|
||||
logger.info(f" 待平仓订单: {orders_to_close}")
|
||||
logger.info(f" 待平仓订单: {orders_to_close}")
|
||||
|
||||
closed_count = 0
|
||||
for order_id in orders_to_close:
|
||||
try:
|
||||
# 先获取订单信息
|
||||
order_info = self.paper_trading.get_order_by_id(order_id)
|
||||
if not order_info:
|
||||
logger.warning(f" ❌ 订单不存在: {order_id}")
|
||||
continue
|
||||
closed_count = 0
|
||||
for order_id in orders_to_close:
|
||||
try:
|
||||
# 先获取订单信息
|
||||
order_info = self.paper_trading.get_order_by_id(order_id)
|
||||
if not order_info:
|
||||
logger.warning(f" ❌ 订单不存在: {order_id}")
|
||||
continue
|
||||
|
||||
status = order_info.get('status')
|
||||
status = order_info.get('status')
|
||||
|
||||
if status == 'PENDING':
|
||||
# 取消挂单
|
||||
result = self.paper_trading.cancel_order(order_id)
|
||||
if result.get('success'):
|
||||
logger.info(f" ✅ 已取消挂单: {order_id}")
|
||||
closed_count += 1
|
||||
else:
|
||||
logger.warning(f" ❌ 取消挂单失败: {order_id} - {result.get('message')}")
|
||||
elif status in ('OPEN', 'FILLED'):
|
||||
# 平仓已成交订单
|
||||
result = self.paper_trading.close_order_manual(order_id, current_price)
|
||||
if result:
|
||||
logger.info(f" ✅ 已平仓: {order_id} @ ${current_price}")
|
||||
closed_count += 1
|
||||
else:
|
||||
logger.warning(f" ❌ 平仓失败: {order_id}")
|
||||
if status == 'PENDING':
|
||||
# 取消挂单
|
||||
result = self.paper_trading.cancel_order(order_id)
|
||||
if result.get('success'):
|
||||
logger.info(f" ✅ 已取消挂单: {order_id}")
|
||||
closed_count += 1
|
||||
else:
|
||||
logger.warning(f" ⚠️ 订单状态无需处理: {order_id} - {status}")
|
||||
except Exception as e:
|
||||
logger.error(f" ❌ 处理订单 {order_id} 失败: {e}")
|
||||
logger.warning(f" ❌ 取消挂单失败: {order_id} - {result.get('message')}")
|
||||
elif status in ('OPEN', 'FILLED'):
|
||||
# 平仓已成交订单
|
||||
result = self.paper_trading.close_order_manual(order_id, current_price)
|
||||
if result:
|
||||
logger.info(f" ✅ 已平仓: {order_id} @ ${current_price}")
|
||||
closed_count += 1
|
||||
else:
|
||||
logger.warning(f" ❌ 平仓失败: {order_id}")
|
||||
else:
|
||||
logger.warning(f" ⚠️ 订单状态无需处理: {order_id} - {status}")
|
||||
except Exception as e:
|
||||
logger.error(f" ❌ 处理订单 {order_id} 失败: {e}")
|
||||
|
||||
logger.info(f" 📊 平仓汇总: {closed_count}/{len(orders_to_close)} 个订单已处理")
|
||||
return closed_count > 0
|
||||
else:
|
||||
logger.warning(f" 交易服务未初始化")
|
||||
return False
|
||||
logger.info(f" 📊 平仓汇总: {closed_count}/{len(orders_to_close)} 个订单已处理")
|
||||
return closed_count > 0
|
||||
else:
|
||||
# 实盘平仓
|
||||
if self.real_trading and self.real_trading.get_auto_trading_status():
|
||||
logger.info(f" 🔒 实盘平仓: {symbol}")
|
||||
logger.info(f" 理由: {decision.get('reasoning', '')}")
|
||||
# TODO: 实现实盘平仓逻辑
|
||||
return True
|
||||
else:
|
||||
logger.warning(f" 实盘交易服务未启用或自动交易未开启")
|
||||
return False
|
||||
logger.warning(f" 交易服务未初始化")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"执行平仓失败: {e}")
|
||||
@ -1604,12 +1415,11 @@ class CryptoAgent:
|
||||
logger.error(traceback.format_exc())
|
||||
return False
|
||||
|
||||
async def _execute_cancel_pending(self, decision: Dict[str, Any], paper_trading: bool = True) -> bool:
|
||||
async def _execute_cancel_pending(self, decision: Dict[str, Any]) -> bool:
|
||||
"""执行取消挂单
|
||||
|
||||
Args:
|
||||
decision: 交易决策
|
||||
paper_trading: True=模拟交易, False=实盘交易
|
||||
|
||||
Returns:
|
||||
是否成功取消订单
|
||||
@ -1621,14 +1431,13 @@ class CryptoAgent:
|
||||
|
||||
if not orders_to_cancel:
|
||||
logger.info(f" ⚠️ 没有需要取消的订单")
|
||||
return
|
||||
return False
|
||||
|
||||
trading_service = self.paper_trading if paper_trading else self.real_trading
|
||||
trading_type = "模拟" if paper_trading else "实盘"
|
||||
trading_service = self.paper_trading
|
||||
|
||||
if not trading_service:
|
||||
logger.warning(f" {trading_type}交易服务未启用")
|
||||
return
|
||||
logger.warning(f" 交易服务未启用")
|
||||
return False
|
||||
|
||||
# 安全检查:验证要取消的订单是否属于当前symbol且方向相反
|
||||
active_orders = trading_service.get_active_orders()
|
||||
@ -1681,7 +1490,7 @@ class CryptoAgent:
|
||||
logger.warning(f" ⚠️ 没有有效的订单可以取消")
|
||||
return False
|
||||
|
||||
logger.info(f" 🚫 {trading_type}取消挂单: {symbol}")
|
||||
logger.info(f" 🚫 取消挂单: {symbol}")
|
||||
logger.info(f" 取消订单数量: {len(valid_orders)}")
|
||||
|
||||
cancelled_count = 0
|
||||
@ -1704,12 +1513,11 @@ class CryptoAgent:
|
||||
logger.error(f"执行取消挂单失败: {e}")
|
||||
return False
|
||||
|
||||
async def _execute_update_pending(self, decision: Dict[str, Any], paper_trading: bool = True) -> bool:
|
||||
async def _execute_update_pending(self, decision: Dict[str, Any]) -> bool:
|
||||
"""执行更新挂单参数
|
||||
|
||||
Args:
|
||||
decision: 交易决策
|
||||
paper_trading: True=模拟交易, False=实盘交易
|
||||
|
||||
Returns:
|
||||
是否成功更新订单
|
||||
@ -1732,11 +1540,10 @@ class CryptoAgent:
|
||||
logger.warning(f" ⚠️ 更新参数不完整: entry_price={new_entry_price}, stop_loss={new_stop_loss}, take_profit={new_take_profit}")
|
||||
return False
|
||||
|
||||
trading_service = self.paper_trading if paper_trading else self.real_trading
|
||||
trading_type = "模拟" if paper_trading else "实盘"
|
||||
trading_service = self.paper_trading
|
||||
|
||||
if not trading_service:
|
||||
logger.warning(f" {trading_type}交易服务未启用")
|
||||
logger.warning(f" 交易服务未启用")
|
||||
return False
|
||||
|
||||
# 安全检查:验证要更新的订单是否属于当前symbol且方向相同
|
||||
@ -1792,7 +1599,7 @@ class CryptoAgent:
|
||||
logger.warning(f" ⚠️ 没有有效的订单可以更新")
|
||||
return False
|
||||
|
||||
logger.info(f" 🔄 {trading_type}更新挂单: {symbol}")
|
||||
logger.info(f" 🔄 更新挂单: {symbol}")
|
||||
logger.info(f" 新参数: 入场=${new_entry_price:,.2f}, 止损=${new_stop_loss:,.2f}, 止盈=${new_take_profit:,.2f}")
|
||||
|
||||
updated_count = 0
|
||||
@ -1822,27 +1629,25 @@ class CryptoAgent:
|
||||
logger.error(f"执行更新挂单失败: {e}")
|
||||
return False
|
||||
|
||||
async def _execute_reduce(self, decision: Dict[str, Any], paper_trading: bool = True) -> bool:
|
||||
async def _execute_reduce(self, decision: Dict[str, Any]) -> bool:
|
||||
"""执行减仓
|
||||
|
||||
Args:
|
||||
decision: 交易决策
|
||||
paper_trading: True=模拟交易, False=实盘交易
|
||||
|
||||
Returns:
|
||||
是否成功执行减仓
|
||||
"""
|
||||
try:
|
||||
symbol = decision.get('symbol')
|
||||
trading_type = "模拟" if paper_trading else "实盘"
|
||||
|
||||
logger.info(f" 📤 {trading_type}减仓: {symbol}")
|
||||
logger.info(f" 📤 减仓: {symbol}")
|
||||
logger.info(f" 理由: {decision.get('reasoning', '')}")
|
||||
|
||||
trading_service = self.paper_trading if paper_trading else self.real_trading
|
||||
trading_service = self.paper_trading
|
||||
|
||||
if not trading_service:
|
||||
logger.warning(f" {trading_type}交易服务未初始化")
|
||||
logger.warning(f" 交易服务未初始化")
|
||||
return False
|
||||
|
||||
# TODO: 实现减仓逻辑
|
||||
@ -1990,44 +1795,6 @@ class CryptoAgent:
|
||||
'trend': signal.get('trend')
|
||||
}
|
||||
|
||||
async def _notify_real_order_created(
|
||||
self,
|
||||
symbol: str,
|
||||
signal: Dict[str, Any],
|
||||
result: Dict[str, Any]
|
||||
):
|
||||
"""发送实盘订单创建通知"""
|
||||
side = signal.get('action', 'buy')
|
||||
side_text = "做多" if side == 'buy' else "做空"
|
||||
side_icon = "🟢" if side == 'buy' else "🔴"
|
||||
grade = signal.get('grade', 'N/A')
|
||||
position_size = result.get('position_size', 'light')
|
||||
quantity = result.get('quantity', 0) # 这是保证金金额
|
||||
position_value = quantity * 20 # 持仓价值 = 保证金 × 杠杆
|
||||
|
||||
title = f"💰 实盘订单已创建 - {symbol}"
|
||||
|
||||
content_parts = [
|
||||
f"{side_icon} **方向**: {side_text}",
|
||||
f"⭐ **信号等级**: {grade}",
|
||||
f"📊 **仓位**: {position_size}",
|
||||
f"💰 **持仓价值**: ${position_value:,.2f}",
|
||||
f"🆔 **订单ID**: {result.get('order_id', '')[:12]}...",
|
||||
f"",
|
||||
f"⚠️ **真实资金交易中**",
|
||||
]
|
||||
|
||||
content = "\n".join(content_parts)
|
||||
|
||||
if self.settings.feishu_enabled:
|
||||
await self.feishu_paper.send_card(title, content, "red")
|
||||
if self.settings.telegram_enabled:
|
||||
message = f"{title}\n\n{content}"
|
||||
await self.telegram.send_message(message)
|
||||
if self.settings.dingtalk_enabled:
|
||||
await self.dingtalk.send_action_card(title, content)
|
||||
logger.info(f"已发送实盘订单创建通知: {result.get('order_id')}")
|
||||
|
||||
async def _notify_position_adjustment(
|
||||
self,
|
||||
symbol: str,
|
||||
@ -2085,13 +1852,12 @@ class CryptoAgent:
|
||||
market_signal: Dict[str, Any],
|
||||
decision: Dict[str, Any],
|
||||
current_price: float,
|
||||
is_paper: bool = True,
|
||||
reason: str = ""
|
||||
):
|
||||
"""发送有信号但未执行交易的通知"""
|
||||
try:
|
||||
symbol = market_signal.get('symbol')
|
||||
account_type = "📊" if is_paper else "💰"
|
||||
account_type = "📊"
|
||||
|
||||
# 获取最佳信号
|
||||
best_signal = self._get_best_signal_from_market(market_signal)
|
||||
|
||||
@ -129,45 +129,77 @@ class TradingDecisionMaker:
|
||||
3. **HOLD(观望)** - 如果反转信号不强
|
||||
|
||||
#### 情况C:无持仓 + 有同向挂单
|
||||
**优先选择:UPDATE_PENDING(更新挂单参数)**
|
||||
**优先选择:OPEN(新增挂单)- 金字塔式布局**
|
||||
|
||||
**核心原则:适应新信号,不要等老信号**
|
||||
- 新信号代表最新的市场分析
|
||||
- 应该用新信号的参数更新挂单
|
||||
- 不要死守过时的挂单价格
|
||||
**核心原则:允许合理的多挂单策略**
|
||||
- 同方向可以最多有3个挂单(金字塔布局)
|
||||
- 新挂单价格与现有挂单价格差异 > 1%
|
||||
- 不同价格位分散风险,提高成交概率
|
||||
|
||||
**更新挂单的条件**:
|
||||
- ✅ 新信号与挂单**方向相同**(都是 buy 或都是 sell)
|
||||
- ✅ 新信号提供了**更新的入场价、止损、止盈**
|
||||
**允许新增挂单的条件**:
|
||||
- ✅ 当前同向挂单数量 < 3个
|
||||
- ✅ 新信号入场价与所有现有挂单价格差异 > 1%
|
||||
- ✅ 新信号置信度 >= 60(C级以上)
|
||||
- ✅ 价格没有在快速加速移动
|
||||
|
||||
**更新内容**(根据新信号调整):
|
||||
- 入场价格:使用新信号的 entry_price
|
||||
- 止损价格:使用新信号的 stop_loss
|
||||
- 止盈价格:使用新信号的 take_profit
|
||||
- 入场方式:保持 limit(不要改成 market)
|
||||
|
||||
**示例**:
|
||||
**示例1:新增第2个挂单**
|
||||
```
|
||||
当前:BTC 做多挂单 @ $94,000,止损 $93,500,止盈 $95,500
|
||||
新信号:BTC 做多 @ $93,800(B级,75%置信度),止损 $93,200,止盈 $95,200
|
||||
当前:BTC 做多挂单1 @ $94,000
|
||||
新信号:BTC 做多 @ $92,700(B级,75%置信度)
|
||||
|
||||
分析:
|
||||
- 新信号更保守,入场价更低
|
||||
- 应该更新挂单参数以适应新的市场分析
|
||||
- 决策:UPDATE_PENDING(更新挂单)
|
||||
- 理由:根据新信号更新入场价 $93,800,止损 $93,200,止盈 $95,200
|
||||
- 价格差异:(94000-92700)/94000 = 1.38% > 1%
|
||||
- 挂单数量:1个 < 3个
|
||||
- 决策:OPEN(新增挂单2 @ $92,700)
|
||||
- 理由:金字塔布局,在不同价位布置挂单
|
||||
```
|
||||
|
||||
**示例2:新增第3个挂单**
|
||||
```
|
||||
当前:BTC 做多挂单1 @ $94,000,挂单2 @ $92,700
|
||||
新信号:BTC 做多 @ $91,500(B级,70%置信度)
|
||||
|
||||
分析:
|
||||
- 新价格与挂单2差异:(92700-91500)/92700 = 1.29% > 1%
|
||||
- 挂单数量:2个 < 3个
|
||||
- 决策:OPEN(新增挂单3 @ $91,500)
|
||||
- 理由:金字塔布局,继续分散挂单位置
|
||||
```
|
||||
|
||||
**示例3:达到3个挂单上限**
|
||||
```
|
||||
当前:BTC 做多挂单1 @ $94,000,挂单2 @ $92,700,挂单3 @ $91,500
|
||||
新信号:BTC 做多 @ $90,800(B级,70%置信度)
|
||||
|
||||
分析:
|
||||
- 已有3个挂单,达到上限
|
||||
- 决策:HOLD
|
||||
- 理由:同向挂单已达3个上限,不再新增
|
||||
```
|
||||
|
||||
**示例4:价格差异太小**
|
||||
```
|
||||
当前:BTC 做多挂单1 @ $94,000
|
||||
新信号:BTC 做多 @ $93,200(价格差异仅0.85%)
|
||||
|
||||
分析:
|
||||
- 价格差异:(94000-93200)/94000 = 0.85% < 1%
|
||||
- 太接近现有挂单,没有意义
|
||||
- 决策:HOLD
|
||||
- 理由:新价格与现有挂单太近,不新增
|
||||
```
|
||||
|
||||
**⚠️ 例外情况(保持 HOLD)**:
|
||||
- 价格正在快速加速移动(5m 连续大阳/阴线)
|
||||
- 新信号置信度 < 60(D级信号,质量太低)
|
||||
- 新信号入场价距离当前价格 >= 2%(追涨杀跌风险)
|
||||
- 新信号是 market 入场(不要改成 market 去追)
|
||||
- 新信号是 market 入场(改成 market 去追)
|
||||
- 价格差异 < 1%(太接近现有挂单)
|
||||
|
||||
**❌ 严禁**:
|
||||
- 同向挂单数量 >= 3个时继续新增
|
||||
- 价格差异 < 1% 时新增挂单
|
||||
- 取消挂单后市价追涨/杀跌
|
||||
- 价格快速移动时的任何更新操作
|
||||
|
||||
#### 情况D:无持仓 + 有反向挂单
|
||||
**优先选择**:
|
||||
@ -177,19 +209,29 @@ class TradingDecisionMaker:
|
||||
#### 情况E:完全无持仓无挂单
|
||||
**这时才考虑开新仓(OPEN)**
|
||||
|
||||
### 第三步:开新仓的严格限制
|
||||
只有在满足以下所有条件时才开新仓:
|
||||
- 当前交易对**没有任何持仓和挂单**
|
||||
### 第三步:开新仓的规则
|
||||
**金字塔式挂单策略**:
|
||||
- 无持仓无挂单:可以开新仓
|
||||
- 无持仓 + 同向挂单 < 3个:可以新增挂单(价格差异 > 1%)
|
||||
- 无持仓 + 同向挂单 >= 3个:不再新增
|
||||
- 有持仓 + 无同向挂单:可以考虑加仓
|
||||
- 有持仓 + 有同向挂单:优先持仓,挂单次之
|
||||
|
||||
**开新仓条件**:
|
||||
- 信号质量足够高(confidence >= 60)
|
||||
- 可用杠杆空间充足
|
||||
- 价格和止损合理
|
||||
- 不在价格加速移动中
|
||||
|
||||
## 🚨 铁律(违反即拒绝)
|
||||
|
||||
### 1. 避免重复开仓
|
||||
- **同一标的同一方向最多只允许1个持仓 + 1个挂单**
|
||||
- 如果已有持仓/挂单,不要开新仓,考虑加仓或调整
|
||||
- 价格距离 < 2% 时不加仓也不开新仓
|
||||
### 1. 金字塔挂单规则(同方向)
|
||||
- **最多3个挂单**:同一标的同一方向最多允许3个挂单
|
||||
- **价格差异 > 1%**:新挂单与现有挂单价格差异必须 > 1%
|
||||
- **挂单优先**:优先使用 limit 挂单,慎用 market 市价
|
||||
- **不要重复**:价格差异 < 1% 时不要新增挂单
|
||||
- **有持仓时**:优先考虑持仓管理,挂单次之
|
||||
- **价格距离 < 2% 时不加仓**:与持仓价格太近时不加仓
|
||||
|
||||
### 2. 趋势与信号一致性
|
||||
| 当前趋势 | 信号方向 | 允许操作 |
|
||||
@ -248,7 +290,7 @@ class TradingDecisionMaker:
|
||||
## 输出格式
|
||||
```json
|
||||
{
|
||||
"decision": "OPEN/CLOSE/ADD/REDUCE/CANCEL_PENDING/UPDATE_PENDING/HOLD",
|
||||
"decision": "OPEN/CLOSE/ADD/REDUCE/CANCEL_PENDING/HOLD",
|
||||
"action": "buy/sell",
|
||||
"quantity": 保证金金额(USDT),
|
||||
"entry_price": 入场价格,
|
||||
@ -256,7 +298,6 @@ class TradingDecisionMaker:
|
||||
"take_profit": 止盈价格,
|
||||
"orders_to_close": ["order_id_1"], // CLOSE/REDUCE 时指定要平仓的订单ID
|
||||
"orders_to_cancel": ["order_id_1"], // CANCEL_PENDING 时指定要取消的订单ID
|
||||
"orders_to_update": ["order_id_1"], // UPDATE_PENDING 时指定要更新的订单ID
|
||||
"reasoning": "决策理由(必须说明当前持仓/挂单状态以及为什么选择这个操作)",
|
||||
"risk_analysis": "风险分析"
|
||||
}
|
||||
@ -265,7 +306,7 @@ class TradingDecisionMaker:
|
||||
**重要提示**:
|
||||
- 当 `decision` 为 `CLOSE` 时,**必须**在 `orders_to_close` 中指定要平仓的订单ID列表
|
||||
- 当 `decision` 为 `CANCEL_PENDING` 时,**必须**在 `orders_to_cancel` 中指定要取消的订单ID列表
|
||||
- 当 `decision` 为 `UPDATE_PENDING` 时,**必须**在 `orders_to_update` 中指定要更新的订单ID列表,并提供新的 entry_price、stop_loss、take_profit
|
||||
- 同方向允许最多3个挂单(金字塔布局),价格差异需 > 1%
|
||||
- 如果需要平仓所有持仓,`orders_to_close` 应包含所有持仓订单的ID
|
||||
|
||||
## 决策示例
|
||||
@ -320,21 +361,44 @@ class TradingDecisionMaker:
|
||||
- 理由:趋势反转,及时止损
|
||||
```
|
||||
|
||||
### 示例5:有挂单 + 同向信号 - 更新挂单参数(UPDATE_PENDING)
|
||||
### 示例5:有挂单 + 同向信号 - 金字塔布局(OPEN)
|
||||
```
|
||||
当前状态:BTC 做多挂单 @ $94,500(未成交),订单ID: ord_456
|
||||
新信号:BTC 做多 @ $93,800(confidence 75%,B级,回调至支撑位)
|
||||
当前状态:BTC 做多挂单1 @ $94,500(未成交),订单ID: ord_456
|
||||
新信号:BTC 做多 @ $93,500(confidence 75%,B级,回调至支撑位)
|
||||
|
||||
分析:
|
||||
- 新信号提供了更优的入场价格($93,800 < $94,500)
|
||||
- 市场出现回调机会,应该调整挂单价格
|
||||
- 决策:UPDATE_PENDING(更新挂单参数)
|
||||
- orders_to_update: ["ord_456"]
|
||||
- 新参数:entry_price=$93,800, stop_loss=$93,200, take_profit=$95,200
|
||||
- 理由:根据新信号更新挂单参数,适应新的市场分析
|
||||
- 同向挂单数量:1个 < 3个
|
||||
- 价格差异:(94500-93500)/94500 = 1.06% > 1%
|
||||
- 满足金字塔布局条件
|
||||
- 决策:OPEN(新增挂单2)
|
||||
- 理由:金字塔布局,在不同价位布置挂单,提高成交概率
|
||||
```
|
||||
|
||||
### 示例6:有挂单 + 同向信号 - 价格加速时保持(HOLD)
|
||||
### 示例6:有挂单 + 同向信号 - 价格差异太小(HOLD)
|
||||
```
|
||||
当前状态:BTC 做多挂单1 @ $94,500,挂单2 @ $93,500
|
||||
新信号:BTC 做多 @ $93,000(confidence 70%,B级)
|
||||
|
||||
分析:
|
||||
- 同向挂单数量:2个 < 3个
|
||||
- 新价格与挂单2差异:(93500-93000)/93500 = 0.53% < 1%
|
||||
- 太接近现有挂单
|
||||
- 决策:HOLD
|
||||
- 理由:新价格与现有挂单太近,不新增
|
||||
```
|
||||
|
||||
### 示例7:有挂单 + 同向信号 - 达到上限(HOLD)
|
||||
```
|
||||
当前状态:BTC 做多挂单1 @ $94,500,挂单2 @ $93,500,挂单3 @ $92,500
|
||||
新信号:BTC 做多 @ $91,500(confidence 70%,B级)
|
||||
|
||||
分析:
|
||||
- 同向挂单数量:3个(已达上限)
|
||||
- 决策:HOLD
|
||||
- 理由:同向挂单已达3个上限,不再新增
|
||||
```
|
||||
|
||||
### 示例8:有挂单 + 同向信号 - 价格加速(HOLD)
|
||||
```
|
||||
当前状态:BTC 做多挂单 @ $94,000(未成交)
|
||||
新信号:BTC 做多 @ $97,000(confidence 85%,B级,突破)
|
||||
@ -347,7 +411,7 @@ class TradingDecisionMaker:
|
||||
- 理由:价格正在加速,禁止追涨杀跌,等待回调
|
||||
```
|
||||
|
||||
### 示例7:完全无持仓无挂单
|
||||
### 示例9:完全无持仓无挂单
|
||||
```
|
||||
当前状态:无持仓,无挂单
|
||||
新信号:BTC 做多 @ $95,000(confidence 80%,uptrend)
|
||||
@ -980,7 +1044,7 @@ class TradingDecisionMaker:
|
||||
market_signal: Dict[str, Any] = None) -> Dict[str, Any]:
|
||||
"""验证决策安全性"""
|
||||
# 检查杠杆限制
|
||||
if decision.get('decision') in ['OPEN', 'ADD', 'UPDATE_PENDING']:
|
||||
if decision.get('decision') in ['OPEN', 'ADD']:
|
||||
balance = float(account.get('current_balance', 0))
|
||||
total_position_value = float(account.get('total_position_value', 0))
|
||||
max_leverage = 20
|
||||
@ -999,7 +1063,6 @@ class TradingDecisionMaker:
|
||||
)
|
||||
|
||||
# 盈亏比检查:所有交易必须满足盈亏比 >= 1:1.5
|
||||
# UPDATE_PENDING 也需要验证盈亏比
|
||||
action = decision.get('action', '')
|
||||
entry_price = decision.get('entry_price')
|
||||
stop_loss = decision.get('stop_loss')
|
||||
|
||||
@ -358,7 +358,7 @@ class PaperTradingService:
|
||||
|
||||
计算逻辑:
|
||||
- 根据可用保证金的倍数确定持仓价值
|
||||
- micro: 0.8x, light: 1.2x, medium: 2.0x, heavy: 3.0x
|
||||
- micro: 0.5x, light: 1.0x, medium: 1.5x, heavy: 2.0x
|
||||
- 累计持仓价值不超过可用保证金的 15 倍
|
||||
- 保证金 = 持仓价值 / 杠杆
|
||||
|
||||
@ -380,11 +380,11 @@ class PaperTradingService:
|
||||
|
||||
# 根据 position_size 确定倍数(相对于可用保证金)
|
||||
position_multiplier = {
|
||||
'micro': 0.8,
|
||||
'light': 1.2,
|
||||
'medium': 2.0,
|
||||
'heavy': 3.0
|
||||
}.get(position_size, 1.2)
|
||||
'micro': 0.5,
|
||||
'light': 1.0,
|
||||
'medium': 1.5,
|
||||
'heavy': 2.0
|
||||
}.get(position_size, 1.0)
|
||||
|
||||
# 最大累计持仓价值倍数
|
||||
max_total_multiplier = 15.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user