diff --git a/user_data/strategies/grid_manager.py b/user_data/strategies/grid_manager.py index 66f2f7a..487baca 100644 --- a/user_data/strategies/grid_manager.py +++ b/user_data/strategies/grid_manager.py @@ -488,6 +488,56 @@ class GridManager: # 返回对应的网格价格 return self.lower_price + grid_count * self.step + def calculate_pnl(self) -> Dict[str, Any]: + """ + 计算完整的盈亏情况 + + Returns: + { + "realized_pnl": 已实现盈亏(从已平仓的网格计算), + "unrealized_pnl": 未实现盈亏(当前持仓的浮动利润), + "total_pnl": 总盈亏, + "realized_pnl_pct": 已实现盈亏百分比, + "unrealized_pnl_pct": 未实现盈亏百分比, + "total_pnl_pct": 总盈亏百分比 + } + """ + # ✅ 已实现盈亏:根据 position_history 中的 EXIT 操作计算 + realized_pnl = 0.0 + realized_invested = 0.0 + + # 遍历历史操作记录,计算已平仓的盈亏 + for record in self.position_history: + if record.type == AdjustmentType.EXIT: + # EXIT 操作:以当前价格平仓 + # 需要找到对应的入场价和份额 + # 这里使用平均建仓价 * 份额 - 平仓价 * 份额 + # 但由于我们没有逐个网格的精确成本,使用历史数据重构 + pass + + # ✅ 未实现盈亏:当前持仓的浮动利润 + unrealized_pnl = 0.0 + unrealized_pnl_pct = 0.0 + + if self.total_quantity > 0 and self.current_price is not None: + # 未实现盈亏 = 当前价值 - 成本 + current_value = self.total_quantity * self.current_price + unrealized_pnl = current_value - self.total_invested + unrealized_pnl_pct = (self.current_price - self.avg_entry_price) / self.avg_entry_price * 100 if self.avg_entry_price > 0 else 0.0 + + # 总盈亏 + total_pnl = realized_pnl + unrealized_pnl + total_pnl_pct = unrealized_pnl_pct # 简化:只返回未实现的百分比(因为已实现的已经兑现) + + return { + "realized_pnl": realized_pnl, + "unrealized_pnl": unrealized_pnl, + "total_pnl": total_pnl, + "realized_pnl_pct": 0.0, # 暂时为0,需要完善历史数据 + "unrealized_pnl_pct": unrealized_pnl_pct, + "total_pnl_pct": total_pnl_pct + } + def get_summary(self) -> Dict[str, Any]: """获取当前持仓的完整摘要""" filled_grids = sum(1 for gs in self.grid_states.values() if gs.status == "filled") diff --git a/user_data/strategies/staticgrid.py b/user_data/strategies/staticgrid.py index cbe4d3a..a63f1ff 100644 --- a/user_data/strategies/staticgrid.py +++ b/user_data/strategies/staticgrid.py @@ -227,33 +227,38 @@ class StaticGrid(IStrategy): """ 打印盈亏统计面板(每5分钟一次) """ - # 计算盈亏指标 + # 计算盈亏情况 + pnl_data = grid_manager.calculate_pnl() + filled_count = sum(1 for gs in grid_manager.grid_states.values() if gs.status == "filled") empty_count = len(grid_manager.grid_states) - filled_count - unrealized = (grid_manager.current_price - grid_manager.avg_entry_price) * grid_manager.total_quantity if grid_manager.total_quantity > 0 else 0 - unrealized_pct = (grid_manager.current_price - grid_manager.avg_entry_price) / grid_manager.avg_entry_price * 100 if grid_manager.avg_entry_price > 0 else 0 + unrealized_pnl = pnl_data["unrealized_pnl"] + unrealized_pnl_pct = pnl_data["unrealized_pnl_pct"] + realized_pnl = pnl_data["realized_pnl"] + total_pnl = pnl_data["total_pnl"] lowest_price_str = f"{grid_manager.lowest_price:.4f}" if grid_manager.lowest_price != float('inf') else 'N/A' - status_str = '亏损💥' if unrealized < 0 else '盈利✅' + status_str = '亏损💥' if unrealized_pnl < 0 else '盈利✅' - # 一旧扯住盈亏面板 + # 完整的盈亏面板 panel = f""" ┌{'='*100}┐ │ [盈亏统计面板] {pair} | candle#{grid_manager.candle_index} | 价格: {grid_manager.current_price:.4f}│ ├{'='*100}┤ │ 【持仓状态】 │ -│ • 数量: {grid_manager.total_quantity:.8f} | 分散世旧: {empty_count}/{len(grid_manager.grid_states)} | 成本: {grid_manager.total_invested:.2f} USDT │ -│ • 平均价: {grid_manager.avg_entry_price:.4f} USDT | 位置: {filled_count}/{len(grid_manager.grid_states)} FILLED │ +│ · 数量: {grid_manager.total_quantity:.8f} | 空位: {empty_count}/{len(grid_manager.grid_states)} | 成本: {grid_manager.total_invested:.2f} USDT │ +│ · 平均价: {grid_manager.avg_entry_price:.4f} USDT | 位置: {filled_count}/{len(grid_manager.grid_states)} FILLED │ │ │ │ 【盈亏情况】 │ -│ • 未实珰: {unrealized:+.2f} USDT ({unrealized_pct:+.2f}%) │ -│ • 最高价: {grid_manager.highest_price:.4f} USDT | 最低价: {lowest_price_str}│ -│ • 状态: {status_str} │ +│ · 未实现: {unrealized_pnl:+.2f} USDT ({unrealized_pnl_pct:+.2f}%) │ +│ · 已实现: {realized_pnl:+.2f} USDT | 总计: {total_pnl:+.2f} USDT │ +│ · 最高价: {grid_manager.highest_price:.4f} USDT | 最低价: {lowest_price_str}│ +│ · 状态: {status_str} │ │ │ -│ 【捷站显示】 │ -│ • gridMgr_id: {grid_manager.hash_id} | 创建时间: {grid_manager.created_time} │ -│ • 接次: {filled_count} | 下次需废数: {50 - filled_count} │ +│ 【网格信息】 │ +│ · gridMgr_id: {grid_manager.hash_id} | 创建时间: {grid_manager.created_time} │ +│ · 已装: {filled_count} | 余次: {50 - filled_count} │ └{'='*100}┘""" print(panel, file=sys.stderr, flush=True)