fix(live/shadow): 实例锁第二层——按账户复制策略适配文件(live_3/live_5共用QMT账号被误判重复实例拒启);bullet_trade实例锁判重键=主机+strategy_path+broker+account_identity,同账号多策略是合法场景须路径互异 [vps]
CI/CD / test (push) Successful in 18s
CI/CD / nas-deploy (push) Successful in 26s
CI/CD / nas-verify (push) Successful in 13s

This commit is contained in:
2026-08-14 20:28:14 +08:00
parent e1cafac451
commit b27c3b479c
2 changed files with 39 additions and 2 deletions
+20 -1
View File
@@ -96,6 +96,25 @@ def _snapshot_loop(engine: Any, db: str, account_id: int,
logger.warning("[live-snapshot] 落库失败 (account=%s): %s", account_id, e)
def _instance_adapter(account_id: str) -> Path:
"""按账户复制一份策略适配文件。
bullet_trade 实例锁判重键=主机+strategy_path+broker_type+account_identity;
多实盘共用同一 QMT 账号(合法场景:同账号跑多策略)时 strategy_path 相同会被
误判"重复实例"拒启 → 每账户一份副本(内容同、路径异)即视为不同逻辑实例。
"""
if not account_id:
return ADAPTER_FILE
dst = (Path(__file__).resolve().parent.parent / "runtime"
/ f"live_{account_id}" / ADAPTER_FILE.name)
dst.parent.mkdir(parents=True, exist_ok=True)
if not dst.exists() or dst.read_text(encoding="utf-8") != \
ADAPTER_FILE.read_text(encoding="utf-8"):
import shutil
shutil.copyfile(ADAPTER_FILE, dst)
return dst
def run_live(provider_config: Dict[str, Any] | None = None) -> None:
"""装配 LiveEngine(strategy_file=适配文件 + QmtBroker)并 run(阻塞)。"""
from bullet_trade.core.live_engine import LiveEngine # type: ignore
@@ -116,7 +135,7 @@ def run_live(provider_config: Dict[str, Any] | None = None) -> None:
logger.info("QmtBroker 装配 account=%s data_path=%s", cfg["account"], cfg["mini_path"])
engine = LiveEngine(
ADAPTER_FILE,
_instance_adapter(cfg["account_id"]),
broker_factory=lambda: broker,
# bullet_trade 每实例锁 runtime 目录(单实例设计);多实盘并行须各用独立目录
live_config={"runtime_dir": str(
+19 -1
View File
@@ -121,6 +121,24 @@ def _snapshot_loop(broker: Any, db: str, account_id: int,
logger.warning("[shadow-snapshot] 落库失败 (account=%s): %s", account_id, exc)
def _instance_adapter(account_id: str) -> Path:
"""按账户复制一份策略适配文件(同 runner_live._instance_adapter)。
bullet_trade 实例锁按 strategy_path+broker_type+account_identity 判重;
多影子账户共用 ShadowBroker(同 identity)时须路径互异才不被判重复实例。
"""
if not account_id:
return ADAPTER_FILE
dst = (Path(__file__).resolve().parents[2] / "runtime"
/ f"shadow_{account_id}" / ADAPTER_FILE.name)
dst.parent.mkdir(parents=True, exist_ok=True)
if not dst.exists() or dst.read_text(encoding="utf-8") != \
ADAPTER_FILE.read_text(encoding="utf-8"):
import shutil
shutil.copyfile(ADAPTER_FILE, dst)
return dst
def run_shadow(provider_config: Optional[Dict[str, Any]] = None) -> None:
"""装配 LiveEngine(影子 broker)并 run(阻塞)。"""
from bullet_trade.core.live_engine import LiveEngine # type: ignore
@@ -153,7 +171,7 @@ def run_shadow(provider_config: Optional[Dict[str, Any]] = None) -> None:
)
engine = LiveEngine(
ADAPTER_FILE,
_instance_adapter(cfg["account_id"]),
broker_factory=lambda: broker,
# 独立 runtime 目录:bullet_trade 单实例锁默认 ./runtime,
# 影子与实盘并行(双轨§8)会互抢锁,按账户分目录隔离