Use 100k equity for recommend list when CTP is offline.

When SimNow or live CTP is disconnected, the tradable-products section shows four whitelisted symbols and calculates max lots from a fixed 100,000 capital instead of reference capital in settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-28 09:16:22 +08:00
parent e18d5feb72
commit 0109b59f27
7 changed files with 30 additions and 12 deletions
+2 -2
View File
@@ -811,16 +811,16 @@ def api_symbols_recommended():
"""品种下拉:仅展示当前资金下可开仓品种(与下方可开仓品种表一致)。""" """品种下拉:仅展示当前资金下可开仓品种(与下方可开仓品种表一致)。"""
from recommend_store import recommend_payload from recommend_store import recommend_payload
from trading_context import ( from trading_context import (
get_account_capital,
get_fixed_lots, get_fixed_lots,
get_max_margin_pct, get_max_margin_pct,
get_recommend_capital,
get_sizing_mode, get_sizing_mode,
get_trading_mode, get_trading_mode,
) )
conn = get_db() conn = get_db()
try: try:
capital = get_account_capital(conn, get_setting) capital = get_recommend_capital(conn, get_setting)
payload = recommend_payload( payload = recommend_payload(
conn, conn,
live_capital=capital, live_capital=capital,
+1 -1
View File
@@ -61,7 +61,7 @@
### 可开仓品种 ### 可开仓品种
- 按当前权益与保证金上限筛选可开品种,养成开仓纪律、限制仓位 - 按当前权益与保证金上限筛选可开品种,养成开仓纪律、限制仓位
- **权益 ≤20 万** 或 **CTP 未连接** 时,仅展示并可交易:玉米、豆粕、甲醇、螺纹钢(SimNow/实盘一致) - **权益 ≤20 万** 或 **CTP 未连接** 时,仅展示并可交易:玉米、豆粕、甲醇、螺纹钢(SimNow/实盘一致);未连接时最大手数按 **10 万权益** 估算
- **夜盘时段** 仅显示有夜盘品种,并标注「夜盘」 - **夜盘时段** 仅显示有夜盘品种,并标注「夜盘」
- **行业分类**、走势(多头/空头/震荡/转多/转空)、跳空、昨日成交量(手)、成交额 - **行业分类**、走势(多头/空头/震荡/转多/转空)、跳空、昨日成交量(手)、成交额
- 支持行业筛选与多字段排序 - 支持行业筛选与多字段排序
+3 -3
View File
@@ -55,9 +55,9 @@
- 期货下单品种联想 / 下拉 - 期货下单品种联想 / 下拉
- 开仓报单校验(含趋势策略首仓) - 开仓报单校验(含趋势策略首仓)
**SimNow 与实盘规则一致****CTP 未连接** 时,无论系统设置中的参考资金是否大于 20 万,均 **默认20 万以下四品种范围** 展示与校验;连接 CTP 后改用柜台权益判断是否启用上述白名单 **SimNow 与实盘规则一致****CTP 未连接** 时,可开仓表 **当前权益固定10 万** 估算最大手数,并 **仅展示四品种**(玉米、豆粕、甲醇、螺纹钢);与系统设置中的参考资金无关。连接 CTP 后改用柜台权益;若柜台权益 ≤20 万,同样仅上述四品种
页面会提示:「未连接 CTP默认20 万以下账户:仅显示并可交易 玉米、豆粕、甲醇、螺纹钢」。 页面会提示:「未连接 CTP,按 10 万权益估算最大手数,仅显示并可交易 …」。
## 期货下单 · 止盈止损与移动保本 ## 期货下单 · 止盈止损与移动保本
@@ -100,7 +100,7 @@
系统设置中的「参考资金」在 **CTP 未连接** 时用于以损定仓估算;连接后自动改用柜台权益。 系统设置中的「参考资金」在 **CTP 未连接** 时用于以损定仓估算;连接后自动改用柜台权益。
可开仓品种与品种白名单:**未连接 CTP 时一律按 20 万以下四品种范围**(见上文);连接后若柜台权益 ≤20 万,同样仅上述四品种。 可开仓品种与品种白名单:**未连接 CTP 时** 可开仓表按 **10 万权益** 估算最大手数,且仅四品种;连接后若柜台权益 ≤20 万,同样仅上述四品种。
## 首次使用 SimNow ## 首次使用 SimNow
+10 -4
View File
@@ -92,6 +92,7 @@ from trading_context import (
get_max_margin_pct, get_max_margin_pct,
get_pending_order_timeout_min, get_pending_order_timeout_min,
get_pending_order_timeout_sec, get_pending_order_timeout_sec,
get_recommend_capital,
get_risk_percent, get_risk_percent,
get_sizing_mode, get_sizing_mode,
get_trailing_be_tick_buffer, get_trailing_be_tick_buffer,
@@ -148,7 +149,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
schedule_recommend_refresh( schedule_recommend_refresh(
db_path=DB_PATH, db_path=DB_PATH,
get_capital_fn=_capital, get_capital_fn=_recommend_capital,
quote_fn=_main_quote, quote_fn=_main_quote,
init_tables_fn=lambda c: init_strategy_tables(c), init_tables_fn=lambda c: init_strategy_tables(c),
get_mode_fn=lambda: get_trading_mode(get_setting), get_mode_fn=lambda: get_trading_mode(get_setting),
@@ -161,13 +162,16 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
mode = get_trading_mode(get_setting) mode = get_trading_mode(get_setting)
return recommend_payload( return recommend_payload(
conn, conn,
live_capital=_capital(conn), live_capital=_recommend_capital(conn),
max_margin_pct=get_max_margin_pct(get_setting), max_margin_pct=get_max_margin_pct(get_setting),
trading_mode=mode, trading_mode=mode,
sizing_mode=get_sizing_mode(get_setting), sizing_mode=get_sizing_mode(get_setting),
fixed_lots=get_fixed_lots(get_setting), fixed_lots=get_fixed_lots(get_setting),
) )
def _recommend_capital(conn) -> float:
return get_recommend_capital(conn, get_setting)
def _settings_dict() -> dict: def _settings_dict() -> dict:
return { return {
"trading_mode": get_trading_mode(get_setting), "trading_mode": get_trading_mode(get_setting),
@@ -1613,6 +1617,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
mode = get_trading_mode(get_setting) mode = get_trading_mode(get_setting)
ctp_st = ctp_status(mode) ctp_st = ctp_status(mode)
capital = _capital(conn) capital = _capital(conn)
recommend_capital = _recommend_capital(conn)
risk = get_risk_status(conn, active_count=_effective_active_position_count(conn, mode)) risk = get_risk_status(conn, active_count=_effective_active_position_count(conn, mode))
ctp_acc = _ctp_account(mode) if ctp_st.get("connected") else {} ctp_acc = _ctp_account(mode) if ctp_st.get("connected") else {}
active_trend = conn.execute( active_trend = conn.execute(
@@ -1636,6 +1641,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
trading_mode=mode, trading_mode=mode,
trading_mode_label=trading_mode_label(get_setting), trading_mode_label=trading_mode_label(get_setting),
capital=capital, capital=capital,
recommend_capital=recommend_capital,
risk_status=risk, risk_status=risk,
ctp_status=ctp_st, ctp_status=ctp_st,
ctp_account=ctp_acc, ctp_account=ctp_acc,
@@ -2459,7 +2465,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
conn = get_db() conn = get_db()
try: try:
init_strategy_tables(conn) init_strategy_tables(conn)
capital = _capital(conn) capital = _recommend_capital(conn)
mode = get_trading_mode(get_setting) mode = get_trading_mode(get_setting)
rows = refresh_recommend_cache( rows = refresh_recommend_cache(
conn, capital, _main_quote, trading_mode=mode, conn, capital, _main_quote, trading_mode=mode,
@@ -2815,7 +2821,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
start_recommend_worker( start_recommend_worker(
db_path=DB_PATH, db_path=DB_PATH,
get_capital_fn=_capital, get_capital_fn=_recommend_capital,
quote_fn=_main_quote, quote_fn=_main_quote,
init_tables_fn=_init_tables, init_tables_fn=_init_tables,
get_mode_fn=lambda: get_trading_mode(get_setting), get_mode_fn=lambda: get_trading_mode(get_setting),
+4 -1
View File
@@ -20,6 +20,8 @@ logger = logging.getLogger(__name__)
# 权益不超过该值时,仅允许下列品种(可开仓列表、品种下拉、开仓报单) # 权益不超过该值时,仅允许下列品种(可开仓列表、品种下拉、开仓报单)
SMALL_ACCOUNT_CAPITAL_MAX = 200_000.0 SMALL_ACCOUNT_CAPITAL_MAX = 200_000.0
# 未连接 CTP 时,可开仓品种表按该权益估算最大手数(与参考资金设置无关)
DISCONNECTED_RECOMMEND_CAPITAL = 100_000.0
SMALL_ACCOUNT_PRODUCT_THS = frozenset({"c", "m", "MA", "rb"}) SMALL_ACCOUNT_PRODUCT_THS = frozenset({"c", "m", "MA", "rb"})
SMALL_ACCOUNT_SCOPE_LABEL = "玉米、豆粕、甲醇、螺纹钢" SMALL_ACCOUNT_SCOPE_LABEL = "玉米、豆粕、甲醇、螺纹钢"
@@ -27,8 +29,9 @@ SMALL_ACCOUNT_SCOPE_LABEL = "玉米、豆粕、甲醇、螺纹钢"
def small_account_scope_hint(*, ctp_connected: bool = True) -> str: def small_account_scope_hint(*, ctp_connected: bool = True) -> str:
wan = int(SMALL_ACCOUNT_CAPITAL_MAX // 10_000) wan = int(SMALL_ACCOUNT_CAPITAL_MAX // 10_000)
if not ctp_connected: if not ctp_connected:
rec_wan = int(DISCONNECTED_RECOMMEND_CAPITAL // 10_000)
return ( return (
f"未连接 CTP默认{wan}以下账户:" f"未连接 CTP,按 {rec_wan}权益估算最大手数,"
f"仅显示并可交易 {SMALL_ACCOUNT_SCOPE_LABEL}" f"仅显示并可交易 {SMALL_ACCOUNT_SCOPE_LABEL}"
) )
return f"权益 {wan} 万以下仅显示并可交易:{SMALL_ACCOUNT_SCOPE_LABEL}" return f"权益 {wan} 万以下仅显示并可交易:{SMALL_ACCOUNT_SCOPE_LABEL}"
+1 -1
View File
@@ -132,7 +132,7 @@
<div class="card trade-card trade-card-full" id="recommend"> <div class="card trade-card trade-card-full" id="recommend">
<h2>可开仓品种</h2> <h2>可开仓品种</h2>
<div class="card-body"> <div class="card-body">
<p class="hint">最大手数 = floor(权益 × 保证金上限 <strong>{{ max_margin_pct }}%</strong> ÷ 1手保证金);当前权益 <strong class="text-accent" id="rec-capital">{{ '%.2f'|format(capital) }}</strong> 元。 <p class="hint">最大手数 = floor(权益 × 保证金上限 <strong>{{ max_margin_pct }}%</strong> ÷ 1手保证金);当前权益 <strong class="text-accent" id="rec-capital">{{ '%.2f'|format(recommend_capital) }}</strong> 元。
{% if sizing_mode == 'fixed' %}仅显示最大手数 ≥ <strong>{{ fixed_lots }}</strong> 手的品种。{% endif %} {% if sizing_mode == 'fixed' %}仅显示最大手数 ≥ <strong>{{ fixed_lots }}</strong> 手的品种。{% endif %}
{% if small_account_scope %}<span class="text-muted">{{ small_account_scope_hint }}。</span>{% endif %} {% if small_account_scope %}<span class="text-muted">{{ small_account_scope_hint }}。</span>{% endif %}
{% if night_session %}<span class="text-muted">当前为夜盘时段,品种下拉与下表仅显示有夜盘品种;带「夜盘」标记。</span>{% elif not small_account_scope %}<span class="text-muted">有夜盘交易的品种带「夜盘」标记。</span>{% endif %} {% if night_session %}<span class="text-muted">当前为夜盘时段,品种下拉与下表仅显示有夜盘品种;带「夜盘」标记。</span>{% elif not small_account_scope %}<span class="text-muted">有夜盘交易的品种带「夜盘」标记。</span>{% endif %}
+9
View File
@@ -91,6 +91,15 @@ def get_account_capital(conn, get_setting: Callable[[str, str], str]) -> float:
return 0.0 return 0.0
def get_recommend_capital(conn, get_setting: Callable[[str, str], str]) -> float:
"""可开仓品种表用权益:已连接 CTP 用柜台权益,未连接固定 10 万。"""
from product_recommend import DISCONNECTED_RECOMMEND_CAPITAL
if is_ctp_connected(get_setting):
return get_account_capital(conn, get_setting)
return float(DISCONNECTED_RECOMMEND_CAPITAL)
def is_ctp_connected(get_setting: Callable[[str, str], str]) -> bool: def is_ctp_connected(get_setting: Callable[[str, str], str]) -> bool:
"""当前交易模式(SimNow / 实盘)是否已连接 CTP。""" """当前交易模式(SimNow / 实盘)是否已连接 CTP。"""
try: try: