feat: KEY_AUTO_ORDER_ENABLED 三所统一开关,联动关键位自动单与开仓类型
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
"""关键位程序自动下单开关(三所共用,与 POSITION_SIZING_MODE 联动)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Any, Optional, Sequence, Tuple
|
||||
|
||||
from lib.key_monitor.fib_key_monitor_lib import is_fib_key_monitor_type
|
||||
from lib.key_monitor.false_breakout_key_monitor_lib import is_false_breakout_key_monitor_type
|
||||
from lib.key_monitor.key_monitor_full_margin_lib import monitor_type_disallowed_in_full_margin
|
||||
from lib.key_monitor.key_monitor_lib import KEY_MONITOR_AUTO_TYPES, KEY_MONITOR_RS_TYPES
|
||||
from lib.key_monitor.trigger_entry_key_monitor_lib import is_trigger_entry_key_monitor_type
|
||||
from lib.trade.position_sizing_lib import is_full_margin_mode
|
||||
|
||||
KEY_ENTRY_REASON_OPTIONS: Tuple[str, ...] = (
|
||||
"关键位箱体突破",
|
||||
"关键位收敛突破",
|
||||
"关键位斐波0.618",
|
||||
"关键位斐波0.786",
|
||||
"关键位假突破",
|
||||
"关键位回调触价开仓",
|
||||
"关键位突破触价开仓",
|
||||
)
|
||||
|
||||
KEY_ENTRY_REASON_TRIGGER_OPTIONS: frozenset[str] = frozenset(
|
||||
{
|
||||
"关键位回调触价开仓",
|
||||
"关键位突破触价开仓",
|
||||
}
|
||||
)
|
||||
|
||||
KEY_STATS_SEGMENT_KEYS: frozenset[str] = frozenset(
|
||||
{
|
||||
"key_box",
|
||||
"key_conv",
|
||||
"key_fib618",
|
||||
"key_fib786",
|
||||
"key_false_breakout",
|
||||
"key_trigger",
|
||||
}
|
||||
)
|
||||
|
||||
KEY_STATS_TRIGGER_ONLY: frozenset[str] = frozenset({"key_trigger"})
|
||||
|
||||
TREND_MANUAL_ENTRY_REASON_COUNT = 5
|
||||
|
||||
|
||||
def _env_bool(raw: Optional[str], default: bool = False) -> bool:
|
||||
if raw is None:
|
||||
return default
|
||||
return (raw or "").strip().lower() in ("1", "true", "yes", "on")
|
||||
|
||||
|
||||
def load_key_auto_order_enabled(env: Optional[dict] = None) -> bool:
|
||||
e = env if env is not None else os.environ
|
||||
return _env_bool(e.get("KEY_AUTO_ORDER_ENABLED"), default=False)
|
||||
|
||||
|
||||
def is_key_level_entry_reason(reason: str) -> bool:
|
||||
return (reason or "").strip() in KEY_ENTRY_REASON_OPTIONS
|
||||
|
||||
|
||||
def visible_key_entry_reasons(sizing_mode: str, key_auto_enabled: bool) -> Tuple[str, ...]:
|
||||
if not key_auto_enabled:
|
||||
return ()
|
||||
if is_full_margin_mode(sizing_mode):
|
||||
return tuple(x for x in KEY_ENTRY_REASON_OPTIONS if x in KEY_ENTRY_REASON_TRIGGER_OPTIONS)
|
||||
return KEY_ENTRY_REASON_OPTIONS
|
||||
|
||||
|
||||
def effective_entry_reason_options(
|
||||
all_options: Sequence[str],
|
||||
sizing_mode: str,
|
||||
key_auto_enabled: bool,
|
||||
*,
|
||||
trend_manual_count: int = TREND_MANUAL_ENTRY_REASON_COUNT,
|
||||
) -> Tuple[str, ...]:
|
||||
"""复盘/表单下拉:按开关与计仓模式裁剪关键位开仓类型。"""
|
||||
opts = list(all_options)
|
||||
if len(opts) <= trend_manual_count:
|
||||
return tuple(opts)
|
||||
key_visible = set(visible_key_entry_reasons(sizing_mode, key_auto_enabled))
|
||||
out: list[str] = []
|
||||
for i, item in enumerate(opts):
|
||||
if i < trend_manual_count:
|
||||
out.append(item)
|
||||
elif is_key_level_entry_reason(item):
|
||||
if item in key_visible:
|
||||
out.append(item)
|
||||
else:
|
||||
out.append(item)
|
||||
return tuple(out)
|
||||
|
||||
|
||||
def effective_stats_segment_defs(
|
||||
segment_defs: Sequence[Tuple[str, str, Any]],
|
||||
sizing_mode: str,
|
||||
key_auto_enabled: bool,
|
||||
) -> Tuple[Tuple[str, str, Any], ...]:
|
||||
if not key_auto_enabled:
|
||||
hidden = KEY_STATS_SEGMENT_KEYS
|
||||
elif is_full_margin_mode(sizing_mode):
|
||||
hidden = KEY_STATS_SEGMENT_KEYS - KEY_STATS_TRIGGER_ONLY
|
||||
else:
|
||||
hidden = frozenset()
|
||||
return tuple(x for x in segment_defs if x[0] not in hidden)
|
||||
|
||||
|
||||
def is_key_auto_monitor_type(monitor_type: str) -> bool:
|
||||
mt = (monitor_type or "").strip()
|
||||
if mt in KEY_MONITOR_AUTO_TYPES:
|
||||
return True
|
||||
if is_fib_key_monitor_type(mt):
|
||||
return True
|
||||
if is_false_breakout_key_monitor_type(mt):
|
||||
return True
|
||||
if is_trigger_entry_key_monitor_type(mt):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_rs_key_monitor_type(monitor_type: str) -> bool:
|
||||
return (monitor_type or "").strip() in KEY_MONITOR_RS_TYPES
|
||||
|
||||
|
||||
def check_monitor_type_add_allowed(
|
||||
monitor_type: str,
|
||||
sizing_mode: str,
|
||||
key_auto_enabled: bool,
|
||||
) -> Tuple[bool, str]:
|
||||
mt = (monitor_type or "").strip()
|
||||
if is_rs_key_monitor_type(mt):
|
||||
return True, ""
|
||||
if not key_auto_enabled:
|
||||
return False, (
|
||||
"已关闭关键位程序自动单(KEY_AUTO_ORDER_ENABLED=false);"
|
||||
"仅可添加「关键支撑阻力」(微信提醒,不下单)。"
|
||||
)
|
||||
if is_full_margin_mode(sizing_mode):
|
||||
if monitor_type_disallowed_in_full_margin(mt):
|
||||
return False, (
|
||||
"全仓杠杆模式下不可添加箱体/收敛突破、斐波或假突破监控;"
|
||||
"可使用「回调/突破触价开仓」或关键支撑阻力(仅提醒)。"
|
||||
)
|
||||
if not is_key_auto_monitor_type(mt) and not is_rs_key_monitor_type(mt):
|
||||
return False, "监控类型无效"
|
||||
return True, ""
|
||||
|
||||
|
||||
def key_auto_order_env_comment_lines() -> Tuple[str, ...]:
|
||||
return (
|
||||
"# 关键位程序自动下单(与 POSITION_SIZING_MODE 联动,修改后须重启 PM2)",
|
||||
"# 默认 false = 关闭所有关键位程序自动单(箱体/收敛/斐波/假突破/触价)",
|
||||
"#",
|
||||
"# POSITION_SIZING_MODE=risk(以损定仓)",
|
||||
"# false → 不执行任何关键位自动单;支撑/阻力提醒、人工下单、顺势加仓不受影响",
|
||||
"# true → 允许关键位全套自动(含触价)",
|
||||
"#",
|
||||
"# POSITION_SIZING_MODE=full_margin(全仓杠杆,须无仓切换)",
|
||||
"# false → 不执行触价自动单",
|
||||
"# true → 仅回调/突破触价可程序自动开仓;箱体/斐波等仍禁止",
|
||||
"#",
|
||||
"# 顺势加仓、趋势回调不受本开关控制;全仓模式下策略自动仍禁止。",
|
||||
"KEY_AUTO_ORDER_ENABLED=false",
|
||||
)
|
||||
Reference in New Issue
Block a user