fix: show risk amount only in full-margin mode across four exchanges
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -88,11 +88,13 @@ from position_sizing_lib import (
|
|||||||
OPEN_SOURCE_TREND,
|
OPEN_SOURCE_TREND,
|
||||||
assert_open_source_allowed,
|
assert_open_source_allowed,
|
||||||
compute_full_margin_sizing,
|
compute_full_margin_sizing,
|
||||||
|
format_risk_display_text,
|
||||||
full_margin_requires_flat_position,
|
full_margin_requires_flat_position,
|
||||||
is_full_margin_mode,
|
is_full_margin_mode,
|
||||||
leverage_for_full_margin,
|
leverage_for_full_margin,
|
||||||
load_position_sizing_mode,
|
load_position_sizing_mode,
|
||||||
mode_label_zh,
|
mode_label_zh,
|
||||||
|
risk_percent_for_storage,
|
||||||
)
|
)
|
||||||
from key_monitor_full_margin_lib import (
|
from key_monitor_full_margin_lib import (
|
||||||
monitor_type_disallowed_in_full_margin,
|
monitor_type_disallowed_in_full_margin,
|
||||||
@@ -7075,6 +7077,10 @@ def add_order():
|
|||||||
breakeven_offset_pct = float(BREAKEVEN_OFFSET_PCT)
|
breakeven_offset_pct = float(BREAKEVEN_OFFSET_PCT)
|
||||||
breakeven_step_r = float(BREAKEVEN_STEP_R) if float(BREAKEVEN_STEP_R) > 0 else 1.0
|
breakeven_step_r = float(BREAKEVEN_STEP_R) if float(BREAKEVEN_STEP_R) > 0 else 1.0
|
||||||
risk_amount_final = calc_risk_amount_from_plan(direction, trigger_price, stop_loss, margin_capital, leverage) or risk_amount
|
risk_amount_final = calc_risk_amount_from_plan(direction, trigger_price, stop_loss, margin_capital, leverage) or risk_amount
|
||||||
|
risk_percent_db = risk_percent_for_storage(POSITION_SIZING_MODE, risk_percent)
|
||||||
|
risk_display = format_risk_display_text(
|
||||||
|
POSITION_SIZING_MODE, risk_percent, risk_amount_final, decimals=FUNDS_DECIMALS
|
||||||
|
)
|
||||||
if direction == "short":
|
if direction == "short":
|
||||||
breakeven_price = round(float(trigger_price) * (1 - breakeven_offset_pct / 100.0), 8)
|
breakeven_price = round(float(trigger_price) * (1 - breakeven_offset_pct / 100.0), 8)
|
||||||
else:
|
else:
|
||||||
@@ -7084,7 +7090,7 @@ def add_order():
|
|||||||
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
(
|
(
|
||||||
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
||||||
margin_capital, leverage, trade_style, risk_percent, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
margin_capital, leverage, trade_style, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
||||||
breakeven_enabled,
|
breakeven_enabled,
|
||||||
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day,
|
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day,
|
||||||
ORDER_MONITOR_TYPE_MANUAL,
|
ORDER_MONITOR_TYPE_MANUAL,
|
||||||
@@ -7200,7 +7206,7 @@ def add_order():
|
|||||||
"🧾 订单基础信息",
|
"🧾 订单基础信息",
|
||||||
f"🔖 交易所订单 ID:{open_order_id}",
|
f"🔖 交易所订单 ID:{open_order_id}",
|
||||||
f"📈 交易风格:{style_zh}",
|
f"📈 交易风格:{style_zh}",
|
||||||
f"⚠️ 单笔风控风险:{risk_percent}% ≈ {round(float(risk_amount_final), FUNDS_DECIMALS)} U",
|
f"⚠️ 单笔风控风险:{risk_display}",
|
||||||
"📊 仓位配置详情",
|
"📊 仓位配置详情",
|
||||||
f"账户基数:{account_base_display} USDT",
|
f"账户基数:{account_base_display} USDT",
|
||||||
f"合约杠杆:{leverage} 倍",
|
f"合约杠杆:{leverage} 倍",
|
||||||
@@ -7223,7 +7229,7 @@ def add_order():
|
|||||||
send_wechat_msg("\n".join(wx_lines))
|
send_wechat_msg("\n".join(wx_lines))
|
||||||
|
|
||||||
flash_lines = [
|
flash_lines = [
|
||||||
f"实盘开单成功:风格 {trade_style};风险 {risk_percent}%≈{risk_amount_final}U;基数 {margin_capital}U,杠杆 {leverage}x,名义仓位 {notional_value}U,仓位占比 {position_ratio}%,合约数量 {amount}(折算标的 {base_amount}),"
|
f"实盘开单成功:风格 {trade_style};风险 {risk_display};基数 {margin_capital}U,杠杆 {leverage}x,名义仓位 {notional_value}U,仓位占比 {position_ratio}%,合约数量 {amount}(折算标的 {base_amount}),"
|
||||||
f"计划RR {planned_rr if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
f"计划RR {planned_rr if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
||||||
f"本交易日累计开仓:{opens_today_after}",
|
f"本交易日累计开仓:{opens_today_after}",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -521,7 +521,7 @@
|
|||||||
<div class="pos-meta">
|
<div class="pos-meta">
|
||||||
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
||||||
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
||||||
<span class="pos-meta-item">风险: {{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U</span>
|
<span class="pos-meta-item">风险: {% if position_sizing_mode == 'full_margin' %}{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% else %}{{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% endif %}</span>
|
||||||
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
||||||
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -87,11 +87,13 @@ from position_sizing_lib import (
|
|||||||
OPEN_SOURCE_MANUAL,
|
OPEN_SOURCE_MANUAL,
|
||||||
assert_open_source_allowed,
|
assert_open_source_allowed,
|
||||||
compute_full_margin_sizing,
|
compute_full_margin_sizing,
|
||||||
|
format_risk_display_text,
|
||||||
full_margin_requires_flat_position,
|
full_margin_requires_flat_position,
|
||||||
is_full_margin_mode,
|
is_full_margin_mode,
|
||||||
leverage_for_full_margin,
|
leverage_for_full_margin,
|
||||||
load_position_sizing_mode,
|
load_position_sizing_mode,
|
||||||
mode_label_zh,
|
mode_label_zh,
|
||||||
|
risk_percent_for_storage,
|
||||||
)
|
)
|
||||||
from key_monitor_full_margin_lib import (
|
from key_monitor_full_margin_lib import (
|
||||||
monitor_type_disallowed_in_full_margin,
|
monitor_type_disallowed_in_full_margin,
|
||||||
@@ -7141,6 +7143,10 @@ def add_order():
|
|||||||
breakeven_offset_pct = float(BREAKEVEN_OFFSET_PCT)
|
breakeven_offset_pct = float(BREAKEVEN_OFFSET_PCT)
|
||||||
breakeven_step_r = float(BREAKEVEN_STEP_R) if float(BREAKEVEN_STEP_R) > 0 else 1.0
|
breakeven_step_r = float(BREAKEVEN_STEP_R) if float(BREAKEVEN_STEP_R) > 0 else 1.0
|
||||||
risk_amount_final = calc_risk_amount_from_plan(direction, trigger_price, stop_loss, margin_capital, leverage) or risk_amount
|
risk_amount_final = calc_risk_amount_from_plan(direction, trigger_price, stop_loss, margin_capital, leverage) or risk_amount
|
||||||
|
risk_percent_db = risk_percent_for_storage(POSITION_SIZING_MODE, risk_percent)
|
||||||
|
risk_display = format_risk_display_text(
|
||||||
|
POSITION_SIZING_MODE, risk_percent, risk_amount_final, decimals=2
|
||||||
|
)
|
||||||
if direction == "short":
|
if direction == "short":
|
||||||
breakeven_raw = float(trigger_price) * (1 - breakeven_offset_pct / 100.0)
|
breakeven_raw = float(trigger_price) * (1 - breakeven_offset_pct / 100.0)
|
||||||
else:
|
else:
|
||||||
@@ -7151,7 +7157,7 @@ def add_order():
|
|||||||
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
(
|
(
|
||||||
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
||||||
margin_capital, leverage, trade_style, risk_percent, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
margin_capital, leverage, trade_style, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
||||||
breakeven_enabled,
|
breakeven_enabled,
|
||||||
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day,
|
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day,
|
||||||
ORDER_MONITOR_TYPE_MANUAL,
|
ORDER_MONITOR_TYPE_MANUAL,
|
||||||
@@ -7269,7 +7275,7 @@ def add_order():
|
|||||||
"🧾 订单基础信息",
|
"🧾 订单基础信息",
|
||||||
f"🔖 交易所订单 ID:{open_order_id}",
|
f"🔖 交易所订单 ID:{open_order_id}",
|
||||||
f"📈 交易风格:{style_zh}",
|
f"📈 交易风格:{style_zh}",
|
||||||
f"⚠️ 单笔风控风险:{risk_percent}% ≈ {round(float(risk_amount_final), 2)} U",
|
f"⚠️ 单笔风控风险:{risk_display}",
|
||||||
"📊 仓位配置详情",
|
"📊 仓位配置详情",
|
||||||
f"账户基数:{account_base_display} USDT",
|
f"账户基数:{account_base_display} USDT",
|
||||||
f"合约杠杆:{leverage} 倍",
|
f"合约杠杆:{leverage} 倍",
|
||||||
@@ -7292,7 +7298,7 @@ def add_order():
|
|||||||
send_wechat_msg("\n".join(wx_lines))
|
send_wechat_msg("\n".join(wx_lines))
|
||||||
|
|
||||||
flash_lines = [
|
flash_lines = [
|
||||||
f"实盘开单成功:风格 {trade_style};风险 {risk_percent}%≈{round(float(risk_amount_final), 2)}U;基数 {round(float(margin_capital), 2)}U,杠杆 {leverage}x,名义仓位 {format_wechat_scalar_2dp(notional_value)}U,仓位占比 {position_ratio}%,合约张数 {format_wechat_scalar_2dp(amount)}(折算标的 {base_amount}),"
|
f"实盘开单成功:风格 {trade_style};风险 {risk_display};基数 {round(float(margin_capital), 2)}U,杠杆 {leverage}x,名义仓位 {format_wechat_scalar_2dp(notional_value)}U,仓位占比 {position_ratio}%,合约张数 {format_wechat_scalar_2dp(amount)}(折算标的 {base_amount}),"
|
||||||
f"计划RR {format_wechat_scalar_2dp(planned_rr) if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
f"计划RR {format_wechat_scalar_2dp(planned_rr) if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
||||||
f"本交易日累计开仓:{opens_today_after}",
|
f"本交易日累计开仓:{opens_today_after}",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -521,7 +521,7 @@
|
|||||||
<div class="pos-meta">
|
<div class="pos-meta">
|
||||||
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
||||||
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
||||||
<span class="pos-meta-item">风险: {{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U</span>
|
<span class="pos-meta-item">风险: {% if position_sizing_mode == 'full_margin' %}{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% else %}{{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% endif %}</span>
|
||||||
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
||||||
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -39,11 +39,13 @@ from ai_review_lib import build_journal_ai_chart_path, collect_images_for_ai_rev
|
|||||||
from position_sizing_lib import (
|
from position_sizing_lib import (
|
||||||
assert_open_source_allowed,
|
assert_open_source_allowed,
|
||||||
compute_full_margin_sizing,
|
compute_full_margin_sizing,
|
||||||
|
format_risk_display_text,
|
||||||
full_margin_requires_flat_position,
|
full_margin_requires_flat_position,
|
||||||
is_full_margin_mode,
|
is_full_margin_mode,
|
||||||
leverage_for_full_margin,
|
leverage_for_full_margin,
|
||||||
load_position_sizing_mode,
|
load_position_sizing_mode,
|
||||||
mode_label_zh,
|
mode_label_zh,
|
||||||
|
risk_percent_for_storage,
|
||||||
)
|
)
|
||||||
from key_monitor_full_margin_lib import (
|
from key_monitor_full_margin_lib import (
|
||||||
monitor_type_disallowed_in_full_margin,
|
monitor_type_disallowed_in_full_margin,
|
||||||
@@ -6705,6 +6707,10 @@ def add_order():
|
|||||||
breakeven_offset_pct = float(BREAKEVEN_OFFSET_PCT)
|
breakeven_offset_pct = float(BREAKEVEN_OFFSET_PCT)
|
||||||
breakeven_step_r = float(BREAKEVEN_STEP_R) if float(BREAKEVEN_STEP_R) > 0 else 1.0
|
breakeven_step_r = float(BREAKEVEN_STEP_R) if float(BREAKEVEN_STEP_R) > 0 else 1.0
|
||||||
risk_amount_final = calc_risk_amount_from_plan(direction, trigger_price, stop_loss, margin_capital, leverage) or risk_amount
|
risk_amount_final = calc_risk_amount_from_plan(direction, trigger_price, stop_loss, margin_capital, leverage) or risk_amount
|
||||||
|
risk_percent_db = risk_percent_for_storage(POSITION_SIZING_MODE, risk_percent)
|
||||||
|
risk_display = format_risk_display_text(
|
||||||
|
POSITION_SIZING_MODE, risk_percent, risk_amount_final, decimals=2
|
||||||
|
)
|
||||||
if direction == "short":
|
if direction == "short":
|
||||||
breakeven_price = round(float(trigger_price) * (1 - breakeven_offset_pct / 100.0), 8)
|
breakeven_price = round(float(trigger_price) * (1 - breakeven_offset_pct / 100.0), 8)
|
||||||
else:
|
else:
|
||||||
@@ -6714,7 +6720,7 @@ def add_order():
|
|||||||
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
(
|
(
|
||||||
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
||||||
margin_capital, leverage, trade_style, risk_percent, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
margin_capital, leverage, trade_style, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
||||||
breakeven_enabled,
|
breakeven_enabled,
|
||||||
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day
|
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day
|
||||||
)
|
)
|
||||||
@@ -6829,7 +6835,7 @@ def add_order():
|
|||||||
"🧾 订单基础信息",
|
"🧾 订单基础信息",
|
||||||
f"🔖 交易所订单 ID:{open_order_id}",
|
f"🔖 交易所订单 ID:{open_order_id}",
|
||||||
f"📈 交易风格:{style_zh}",
|
f"📈 交易风格:{style_zh}",
|
||||||
f"⚠️ 单笔风控风险:{risk_percent}% ≈ {round(float(risk_amount_final), 4)} U",
|
f"⚠️ 单笔风控风险:{risk_display}",
|
||||||
"📊 仓位配置详情",
|
"📊 仓位配置详情",
|
||||||
f"账户基数:{account_base_display} USDT",
|
f"账户基数:{account_base_display} USDT",
|
||||||
f"合约杠杆:{leverage} 倍",
|
f"合约杠杆:{leverage} 倍",
|
||||||
@@ -6852,7 +6858,7 @@ def add_order():
|
|||||||
send_wechat_msg("\n".join(wx_lines))
|
send_wechat_msg("\n".join(wx_lines))
|
||||||
|
|
||||||
flash_lines = [
|
flash_lines = [
|
||||||
f"机器人开单成功:风格 {trade_style};风险 {risk_percent}%≈{risk_amount_final}U;基数 {margin_capital}U,杠杆 {leverage}x,名义仓位 {notional_value}U,仓位占比 {position_ratio}%,合约张数 {amount}(折算标的 {base_amount}),"
|
f"机器人开单成功:风格 {trade_style};风险 {risk_display};基数 {margin_capital}U,杠杆 {leverage}x,名义仓位 {notional_value}U,仓位占比 {position_ratio}%,合约张数 {amount}(折算标的 {base_amount}),"
|
||||||
f"计划RR {planned_rr if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
f"计划RR {planned_rr if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
||||||
f"本交易日累计开仓:{opens_today_after}",
|
f"本交易日累计开仓:{opens_today_after}",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -468,7 +468,7 @@
|
|||||||
<div class="pos-meta">
|
<div class="pos-meta">
|
||||||
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
||||||
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
||||||
<span class="pos-meta-item">风险: {{ o.risk_percent or '-' }}%≈{{ money_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U</span>
|
<span class="pos-meta-item">风险: {% if position_sizing_mode == 'full_margin' %}{{ money_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% else %}{{ o.risk_percent or '-' }}%≈{{ money_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% endif %}</span>
|
||||||
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
||||||
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -87,11 +87,13 @@ from position_sizing_lib import (
|
|||||||
OPEN_SOURCE_MANUAL,
|
OPEN_SOURCE_MANUAL,
|
||||||
assert_open_source_allowed,
|
assert_open_source_allowed,
|
||||||
compute_full_margin_sizing,
|
compute_full_margin_sizing,
|
||||||
|
format_risk_display_text,
|
||||||
full_margin_requires_flat_position,
|
full_margin_requires_flat_position,
|
||||||
is_full_margin_mode,
|
is_full_margin_mode,
|
||||||
leverage_for_full_margin,
|
leverage_for_full_margin,
|
||||||
load_position_sizing_mode,
|
load_position_sizing_mode,
|
||||||
mode_label_zh,
|
mode_label_zh,
|
||||||
|
risk_percent_for_storage,
|
||||||
)
|
)
|
||||||
from key_monitor_full_margin_lib import (
|
from key_monitor_full_margin_lib import (
|
||||||
monitor_type_disallowed_in_full_margin,
|
monitor_type_disallowed_in_full_margin,
|
||||||
@@ -6757,6 +6759,10 @@ def add_order():
|
|||||||
breakeven_offset_pct = float(BREAKEVEN_OFFSET_PCT)
|
breakeven_offset_pct = float(BREAKEVEN_OFFSET_PCT)
|
||||||
breakeven_step_r = float(BREAKEVEN_STEP_R) if float(BREAKEVEN_STEP_R) > 0 else 1.0
|
breakeven_step_r = float(BREAKEVEN_STEP_R) if float(BREAKEVEN_STEP_R) > 0 else 1.0
|
||||||
risk_amount_final = calc_risk_amount_from_plan(direction, trigger_price, stop_loss, margin_capital, leverage) or risk_amount
|
risk_amount_final = calc_risk_amount_from_plan(direction, trigger_price, stop_loss, margin_capital, leverage) or risk_amount
|
||||||
|
risk_percent_db = risk_percent_for_storage(POSITION_SIZING_MODE, risk_percent)
|
||||||
|
risk_display = format_risk_display_text(
|
||||||
|
POSITION_SIZING_MODE, risk_percent, risk_amount_final, decimals=FUNDS_DECIMALS
|
||||||
|
)
|
||||||
if direction == "short":
|
if direction == "short":
|
||||||
breakeven_price = round(float(trigger_price) * (1 - breakeven_offset_pct / 100.0), 8)
|
breakeven_price = round(float(trigger_price) * (1 - breakeven_offset_pct / 100.0), 8)
|
||||||
else:
|
else:
|
||||||
@@ -6766,7 +6772,7 @@ def add_order():
|
|||||||
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
"INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
(
|
(
|
||||||
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
|
||||||
margin_capital, leverage, trade_style, risk_percent, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
margin_capital, leverage, trade_style, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
|
||||||
breakeven_enabled,
|
breakeven_enabled,
|
||||||
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day, "下单监控",
|
notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day, "下单监控",
|
||||||
)
|
)
|
||||||
@@ -6880,7 +6886,7 @@ def add_order():
|
|||||||
"🧾 订单基础信息",
|
"🧾 订单基础信息",
|
||||||
f"🔖 交易所订单 ID:{open_order_id}",
|
f"🔖 交易所订单 ID:{open_order_id}",
|
||||||
f"📈 交易风格:{style_zh}",
|
f"📈 交易风格:{style_zh}",
|
||||||
f"⚠️ 单笔风控风险:{risk_percent}% ≈ {round(float(risk_amount_final), 2)} U",
|
f"⚠️ 单笔风控风险:{risk_display}",
|
||||||
"📊 仓位配置详情",
|
"📊 仓位配置详情",
|
||||||
f"账户基数:{account_base_display} USDT",
|
f"账户基数:{account_base_display} USDT",
|
||||||
f"合约杠杆:{leverage} 倍",
|
f"合约杠杆:{leverage} 倍",
|
||||||
@@ -6903,7 +6909,7 @@ def add_order():
|
|||||||
send_wechat_msg("\n".join(wx_lines))
|
send_wechat_msg("\n".join(wx_lines))
|
||||||
|
|
||||||
flash_lines = [
|
flash_lines = [
|
||||||
f"实盘开单成功:风格 {trade_style};风险 {risk_percent}%≈{round(float(risk_amount_final), 2)}U;基数 {round(float(margin_capital), 2)}U,杠杆 {leverage}x,名义仓位 {format_wechat_scalar_2dp(notional_value)}U,仓位占比 {position_ratio}%,合约张数 {format_wechat_scalar_2dp(amount)}(折算标的 {base_amount}),"
|
f"实盘开单成功:风格 {trade_style};风险 {risk_display};基数 {round(float(margin_capital), 2)}U,杠杆 {leverage}x,名义仓位 {format_wechat_scalar_2dp(notional_value)}U,仓位占比 {position_ratio}%,合约张数 {format_wechat_scalar_2dp(amount)}(折算标的 {base_amount}),"
|
||||||
f"计划RR {format_wechat_scalar_2dp(planned_rr) if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
f"计划RR {format_wechat_scalar_2dp(planned_rr) if planned_rr is not None else '-'};已在交易所挂条件止盈/止损委托(非仓位绑定型)",
|
||||||
f"本交易日累计开仓:{opens_today_after}",
|
f"本交易日累计开仓:{opens_today_after}",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -530,7 +530,7 @@
|
|||||||
<div class="pos-meta">
|
<div class="pos-meta">
|
||||||
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
<span class="pos-meta-item">来源: {{ o.monitor_type|default('下单监控', true) }}{% if o.key_signal_type %} · {{ o.key_signal_type }}{% endif %}</span>
|
||||||
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
<span class="pos-meta-item">风格: {{ o.trade_style or 'trend' }}</span>
|
||||||
<span class="pos-meta-item">风险: {{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U</span>
|
<span class="pos-meta-item">风险: {% if position_sizing_mode == 'full_margin' %}{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% else %}{{ o.risk_percent or '-' }}%≈{{ funds_fmt(o.risk_amount) if o.risk_amount is not none else '-' }}U{% endif %}</span>
|
||||||
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
<span class="pos-meta-item {% if o.breakeven_enabled %}pos-meta-on{% else %}pos-meta-off{% endif %}">
|
||||||
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
{% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -322,6 +322,34 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatMonitorRiskMeta(mo, trendPlan) {
|
||||||
|
const m = mo || {};
|
||||||
|
const t = trendPlan || {};
|
||||||
|
const amt =
|
||||||
|
m.risk_amount != null && m.risk_amount !== ""
|
||||||
|
? Number(m.risk_amount)
|
||||||
|
: t.risk_amount != null && t.risk_amount !== ""
|
||||||
|
? Number(t.risk_amount)
|
||||||
|
: null;
|
||||||
|
const pctRaw =
|
||||||
|
m.risk_percent != null && m.risk_percent !== ""
|
||||||
|
? m.risk_percent
|
||||||
|
: t.risk_percent != null && t.risk_percent !== ""
|
||||||
|
? t.risk_percent
|
||||||
|
: null;
|
||||||
|
if (pctRaw == null || pctRaw === "") {
|
||||||
|
if (amt != null && Number.isFinite(amt)) {
|
||||||
|
return `风险: ${fmt(amt, 2)}U`;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const pct = esc(pctRaw);
|
||||||
|
if (amt != null && Number.isFinite(amt)) {
|
||||||
|
return `风险: ${pct}%≈${fmt(amt, 2)}U`;
|
||||||
|
}
|
||||||
|
return `风险: ${pct}%`;
|
||||||
|
}
|
||||||
|
|
||||||
function resolveTrendMarkPrice(pos, trendPlan, symbol, tickMap) {
|
function resolveTrendMarkPrice(pos, trendPlan, symbol, tickMap) {
|
||||||
const fromPos = fmtMarkPrice(pos, tickMap);
|
const fromPos = fmtMarkPrice(pos, tickMap);
|
||||||
if (fromPos && fromPos !== "—") return fromPos;
|
if (fromPos && fromPos !== "—") return fromPos;
|
||||||
@@ -1983,13 +2011,8 @@
|
|||||||
const meta = [];
|
const meta = [];
|
||||||
if (isTrend) {
|
if (isTrend) {
|
||||||
meta.push(monitorOrderSourceHtml(mo, trendPlan));
|
meta.push(monitorOrderSourceHtml(mo, trendPlan));
|
||||||
const riskPct =
|
const riskLine = formatMonitorRiskMeta(mo, trendPlan);
|
||||||
trendPlan && trendPlan.risk_percent != null && trendPlan.risk_percent !== ""
|
if (riskLine) meta.push(riskLine);
|
||||||
? trendPlan.risk_percent
|
|
||||||
: mo.risk_percent;
|
|
||||||
if (riskPct != null && riskPct !== "") {
|
|
||||||
meta.push(`风险: ${esc(riskPct)}%`);
|
|
||||||
}
|
|
||||||
if (trendPlan && trendPlan.id) {
|
if (trendPlan && trendPlan.id) {
|
||||||
const zone =
|
const zone =
|
||||||
trendPlan.add_upper_display ||
|
trendPlan.add_upper_display ||
|
||||||
@@ -2006,9 +2029,8 @@
|
|||||||
meta.push(monitorOrderSourceHtml(mo, trendPlan));
|
meta.push(monitorOrderSourceHtml(mo, trendPlan));
|
||||||
if (mo.trade_style) meta.push(`风格: ${esc(mo.trade_style)}`);
|
if (mo.trade_style) meta.push(`风格: ${esc(mo.trade_style)}`);
|
||||||
else meta.push("风格: —");
|
else meta.push("风格: —");
|
||||||
if (mo.risk_percent != null) {
|
const riskLine = formatMonitorRiskMeta(mo, trendPlan);
|
||||||
meta.push(`风险: ${esc(mo.risk_percent)}%`);
|
if (riskLine) meta.push(riskLine);
|
||||||
}
|
|
||||||
const beOn = mo.breakeven_enabled === 1 || mo.breakeven_enabled === true;
|
const beOn = mo.breakeven_enabled === 1 || mo.breakeven_enabled === true;
|
||||||
meta.push(
|
meta.push(
|
||||||
`<span class="${beOn ? "pos-meta-on" : "pos-meta-off"}">移动保本:${beOn ? "开" : "关"}</span>`
|
`<span class="${beOn ? "pos-meta-on" : "pos-meta-off"}">移动保本:${beOn ? "开" : "关"}</span>`
|
||||||
|
|||||||
@@ -250,6 +250,6 @@
|
|||||||
<div id="toast"></div>
|
<div id="toast"></div>
|
||||||
<script src="https://unpkg.com/lightweight-charts@4.2.0/dist/lightweight-charts.standalone.production.js"></script>
|
<script src="https://unpkg.com/lightweight-charts@4.2.0/dist/lightweight-charts.standalone.production.js"></script>
|
||||||
<script src="/assets/chart.js?v=20260604-upnl-contracts"></script>
|
<script src="/assets/chart.js?v=20260604-upnl-contracts"></script>
|
||||||
<script src="/assets/app.js?v=20260604-upnl-contracts"></script>
|
<script src="/assets/app.js?v=20260604-risk-full-margin"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -53,6 +53,42 @@ def round_funds(value: float, decimals: int = 2) -> float:
|
|||||||
return round(float(value), int(decimals))
|
return round(float(value), int(decimals))
|
||||||
|
|
||||||
|
|
||||||
|
def risk_percent_for_storage(mode: str, risk_percent: float) -> Optional[float]:
|
||||||
|
"""全仓杠杆:库内不写风险百分比(仅 risk_amount U)。"""
|
||||||
|
if is_full_margin_mode(mode):
|
||||||
|
return None
|
||||||
|
return risk_percent
|
||||||
|
|
||||||
|
|
||||||
|
def format_risk_display_text(
|
||||||
|
mode: str,
|
||||||
|
risk_percent: Optional[float],
|
||||||
|
risk_amount: Optional[float],
|
||||||
|
*,
|
||||||
|
decimals: int = 2,
|
||||||
|
) -> str:
|
||||||
|
"""持仓/通知「风险」文案:全仓仅 U;以损定仓为 %≈U。"""
|
||||||
|
amt: Optional[float] = None
|
||||||
|
if risk_amount is not None and risk_amount != "":
|
||||||
|
try:
|
||||||
|
amt = float(risk_amount)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
amt = None
|
||||||
|
if is_full_margin_mode(mode):
|
||||||
|
if amt is None:
|
||||||
|
return "—"
|
||||||
|
return f"{round_funds(amt, decimals)}U"
|
||||||
|
pct: Optional[float] = None
|
||||||
|
if risk_percent is not None and risk_percent != "":
|
||||||
|
try:
|
||||||
|
pct = float(risk_percent)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
pct = None
|
||||||
|
pct_txt = f"{pct:g}" if pct is not None else "—"
|
||||||
|
amt_txt = round_funds(amt, decimals) if amt is not None else "—"
|
||||||
|
return f"{pct_txt}%≈{amt_txt}U"
|
||||||
|
|
||||||
|
|
||||||
def assert_open_source_allowed(mode: str, source: str) -> Tuple[bool, str]:
|
def assert_open_source_allowed(mode: str, source: str) -> Tuple[bool, str]:
|
||||||
if not is_full_margin_mode(mode):
|
if not is_full_margin_mode(mode):
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
"""全仓 / 以损定仓 风险展示文案。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
sys.path.insert(0, str(ROOT))
|
||||||
|
|
||||||
|
from position_sizing_lib import ( # noqa: E402
|
||||||
|
format_risk_display_text,
|
||||||
|
risk_percent_for_storage,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPositionSizingRiskDisplay(unittest.TestCase):
|
||||||
|
def test_full_margin_shows_amount_only(self):
|
||||||
|
self.assertEqual(
|
||||||
|
format_risk_display_text("full_margin", 1.0, 2.58, decimals=2),
|
||||||
|
"2.58U",
|
||||||
|
)
|
||||||
|
self.assertIsNone(risk_percent_for_storage("full_margin", 1.0))
|
||||||
|
|
||||||
|
def test_risk_mode_shows_percent_and_amount(self):
|
||||||
|
self.assertEqual(
|
||||||
|
format_risk_display_text("risk", 2.0, 10.5, decimals=2),
|
||||||
|
"2%≈10.5U",
|
||||||
|
)
|
||||||
|
self.assertEqual(risk_percent_for_storage("risk", 2.0), 2.0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user