Add SIM/LIVE switch with API keys saved to .env and OKX live executor.

Enable settings UI for mode/keys, gate strategy start when LIVE is not ready, and stop PM2 from forcing MODE=SIM.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-26 21:08:39 +08:00
parent c2113b1a57
commit e666230d0b
19 changed files with 1367 additions and 33 deletions
+18 -2
View File
@@ -11,7 +11,8 @@ from ..config import get_settings
from .session import get_session
from ..models.db import get_db
from ..sim.ledger import Ledger
from ..sim.matcher import Matcher
from ..live import get_executor
from ..env_store import live_ready
from .clock import can_open_new, window_key
from .exits import check_expiry_close, check_exits, resolve_exit_target
from .group import next_group_id
@@ -22,11 +23,15 @@ logger = logging.getLogger(__name__)
class StrategyEngine:
def __init__(self) -> None:
self.db = get_db()
self.matcher = Matcher(self.db)
self.ledger = Ledger(self.db)
self.matcher = get_executor(self.db)
self._task: asyncio.Task[None] | None = None
self._lock = asyncio.Lock()
def refresh_executor(self) -> None:
"""MODE 变更后刷新执行器。"""
self.matcher = get_executor(self.db)
def state(self) -> dict[str, Any]:
row = self.db.fetchone("SELECT * FROM strategy_state WHERE id=1")
assert row is not None
@@ -90,6 +95,10 @@ class StrategyEngine:
"position": upl,
"residuals": self.matcher.list_residual_options(pending_only=True),
"ledger": self.ledger.snapshot(),
"mode": "SIM" if s.is_sim else "LIVE",
"sim": s.is_sim,
"live_ready": (live_ready()[0] if not s.is_sim else True),
"live_ready_reason": (live_ready()[1] if not s.is_sim else "sim"),
}
def _set_state(self, **kwargs: Any) -> None:
@@ -108,6 +117,13 @@ class StrategyEngine:
return self.state()
async def start(self) -> dict[str, Any]:
self.refresh_executor()
s = get_settings()
if not s.is_sim:
ok, reason = live_ready()
if not ok:
self._set_state(running=0, phase="paused", last_error=reason)
return self.state()
self._set_state(running=1, last_error=None, phase="idle")
self.ensure_loop()
return self.state()