from typing import Iterable, Dict, List, Union
def profit_factor_from_trades_and_positions(
fills: Iterable[Dict], # 每笔已平仓或填充记录,包含字段 closedPnl (float)
asset_positions: Iterable[Dict] # 当前 assetPositions,包含 position.unrealizedPnl (float)
) -> Union[float, str]:
"""
根据 JS 实现还原的 Profit Factor:
- 将所有正的 closedPnl + unrealizedPnl 累加为 wins (s)
- 将所有负的 closedPnl + unrealizedPnl 的绝对值累加为 losses (i)
- 若 losses != 0 则返回 wins / losses
- 若 losses == 0 且 wins > 0 则返回字符串 "1000+"(原码使用类似的显示)
- 否则返回 0.0
注意:参数中的记录格式和字段名需与源数据一致(closedPnl / position.unrealizedPnl)。
"""
from decimal import Decimal
wins = Decimal(0)
losses = Decimal(0)
# 累加 fills 中的 closedPnl(示例中 closedPnl 已经是数字或字符串数值)
for f in fills:
try:
pnl = Decimal(str(f.get("closedPnl", 0) or 0))
except Exception:
pnl = Decimal(0)
if pnl > 0:
wins += pnl
elif pnl < 0:
losses += abs(pnl)
# 累加 asset_positions 中的未实现 pnl(unrealizedPnl)
for ap in asset_positions:
# 许多打包后的结构是 ap.position.unrealizedPnl
pos = ap.get("position") if isinstance(ap, dict) else None
if pos and "unrealizedPnl" in pos:
try:
upnl = Decimal(str(pos.get("unrealizedPnl", 0) or 0))
except Exception:
upnl = Decimal(0)
else:
# 也可能直接在顶层:ap.get("unrealizedPnl")
try:
upnl = Decimal(str(ap.get("unrealizedPnl", 0) or 0))
except Exception:
upnl = Decimal(0)
if upnl > 0:
wins += upnl
elif upnl < 0:
losses += abs(upnl)
# 根据原 JS 逻辑:如果 losses != 0 -> wins / losses
if losses != 0:
# 保持小数精度(可按需 format)
return float(wins / losses)
else:
# losses == 0
if wins > 0:
# 原码显示 "1000+" 的情况
return "1000+"
else:
return 0.0
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)