11
This commit is contained in:
parent
b531ed4055
commit
f684cf746a
@ -66,10 +66,12 @@ class CryptoAgent:
|
||||
'UNI': 5, # 1 UNI/张 ≈ $50
|
||||
},
|
||||
'max_margin_pct': 0.25, # 单笔最大25%(支持超激进配置)
|
||||
'min_position_value_balance_ratio': 1.0, # 合约单最低名义仓位 = 1x 账户权益
|
||||
},
|
||||
'PaperTrading': {
|
||||
'min_margin': {}, # 无最小限制
|
||||
'max_margin_pct': 0.25, # 单笔最大25%(与实盘一致)
|
||||
'min_position_value_balance_ratio': 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -3639,6 +3641,7 @@ class CryptoAgent:
|
||||
|
||||
symbol = signal.get('symbol', '').replace('USDT', '').upper()
|
||||
min_margin = min_margin_rules.get(symbol, 0)
|
||||
min_position_value_balance_ratio = float(rules.get('min_position_value_balance_ratio', 0) or 0)
|
||||
current_leverage = account.get('current_total_leverage', 0)
|
||||
max_leverage = account.get('max_total_leverage', 10)
|
||||
order_leverage = account.get('order_leverage', 10)
|
||||
@ -3679,6 +3682,7 @@ class CryptoAgent:
|
||||
|
||||
setup_margin_pct_cap = setup_profile.get('max_margin_pct_cap')
|
||||
effective_max_margin_pct = min(max_margin_pct, setup_margin_pct_cap) if isinstance(setup_margin_pct_cap, (int, float)) else max_margin_pct
|
||||
min_position_value = balance * min_position_value_balance_ratio if min_position_value_balance_ratio > 0 else 0.0
|
||||
|
||||
margin, _, budget_reason = calculate_margin_and_position_value(
|
||||
balance=balance,
|
||||
@ -3689,6 +3693,7 @@ class CryptoAgent:
|
||||
target_margin_pct=target_margin_pct,
|
||||
max_margin_pct=effective_max_margin_pct,
|
||||
min_margin=min_margin,
|
||||
min_position_value=min_position_value,
|
||||
min_effective_leverage=min_effective_leverage,
|
||||
)
|
||||
|
||||
|
||||
@ -440,6 +440,7 @@ class PaperTradingService:
|
||||
order_leverage=self.leverage,
|
||||
target_margin_pct=target_margin_pct,
|
||||
max_margin_pct=0.25,
|
||||
min_position_value=balance,
|
||||
)
|
||||
|
||||
if margin <= 0:
|
||||
|
||||
@ -115,6 +115,7 @@ def calculate_margin_and_position_value(
|
||||
target_margin_pct: float,
|
||||
max_margin_pct: float,
|
||||
min_margin: float = 0.0,
|
||||
min_position_value: float = 0.0,
|
||||
min_effective_leverage: float = 1.0,
|
||||
reserve_ratio: float = 0.05,
|
||||
) -> Tuple[float, float, str]:
|
||||
@ -152,16 +153,31 @@ def calculate_margin_and_position_value(
|
||||
|
||||
target_margin = balance * target_margin_pct
|
||||
margin = min(target_margin, hard_cap)
|
||||
adjustments = []
|
||||
|
||||
if min_margin > 0 and margin < min_margin:
|
||||
if min_margin <= hard_cap:
|
||||
margin = min_margin
|
||||
adjustments.append(f"按最小保证金抬升至 ${min_margin:.2f}")
|
||||
else:
|
||||
return 0.0, 0.0, (
|
||||
f"最小保证金 ${min_margin:.2f} 超过当前可用额度 "
|
||||
f"${hard_cap:.2f}"
|
||||
)
|
||||
|
||||
if min_position_value > 0:
|
||||
required_margin_for_min_position = min_position_value / order_leverage
|
||||
if margin < required_margin_for_min_position:
|
||||
if required_margin_for_min_position <= hard_cap:
|
||||
margin = required_margin_for_min_position
|
||||
adjustments.append(
|
||||
f"按最低名义仓位 ${min_position_value:.2f} 抬升保证金至 ${margin:.2f}"
|
||||
)
|
||||
else:
|
||||
adjustments.append(
|
||||
f"最低名义仓位 ${min_position_value:.2f} 受当前上限约束,实际最多 ${hard_cap * order_leverage:.2f}"
|
||||
)
|
||||
|
||||
position_value = margin * order_leverage
|
||||
if position_value < 50:
|
||||
return 0.0, 0.0, "可开仓位不足 $50"
|
||||
@ -172,5 +188,7 @@ def calculate_margin_and_position_value(
|
||||
f"目标保证金 ${target_margin:.2f}, 实际保证金 ${margin:.2f}, "
|
||||
f"名义仓位 ${position_value:.2f}, 单笔杠杆 {order_leverage:.1f}x"
|
||||
)
|
||||
if adjustments:
|
||||
detail = f"{detail}, 调整: {'; '.join(adjustments)}"
|
||||
logger.info(f"仓位预算计算: {detail}")
|
||||
return margin, position_value, detail
|
||||
|
||||
@ -165,3 +165,21 @@ def test_setup_profile_can_cap_margin_budget_more_conservatively():
|
||||
|
||||
assert margin == pytest.approx(1320.0)
|
||||
assert position_value == pytest.approx(13200.0)
|
||||
|
||||
|
||||
def test_min_position_value_floor_can_raise_too_small_contract_position():
|
||||
module = load_position_sizing_module()
|
||||
|
||||
margin, position_value, _ = module.calculate_margin_and_position_value(
|
||||
balance=1400,
|
||||
available_margin=1400,
|
||||
current_total_leverage=0,
|
||||
max_total_leverage=10,
|
||||
order_leverage=10,
|
||||
target_margin_pct=0.028, # 原本只会开到约 392U 名义仓位
|
||||
max_margin_pct=0.25,
|
||||
min_position_value=1400,
|
||||
)
|
||||
|
||||
assert margin == pytest.approx(140.0)
|
||||
assert position_value == pytest.approx(1400.0)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user