Global

Exit - 主动退出与生命周期

Exit() 是框架提供的主动退出方法。小写的 exit() 是用户定义的清理回调,与 init()、main() 同级,不能混用。

主动退出

python
Exit()
Exit(reason="达到目标,停止策略")
Exit(code=1, reason="初始化失败")
参数类型默认值说明
codeint0退出码;0 表示正常停止,1–255 表示异常退出,不接受布尔值
reasonstr"策略主动退出"退出原因,记录到日志并随最终状态上报

正常运行期间,调用 Exit() 会中断当前调用栈,不继续执行后面的策略代码。它不会被普通的 except Exception 捕获。不要捕获并吞掉 SystemExit 或 BaseException,否则可能阻止退出。

工作线程也可以调用 Exit():该线程退出,同时通知策略主线程进入清理流程。主线程在取消检查点响应请求,并非强制终止所有工作线程。

生命周期顺序

text
加载并校验策略
    ↓
init():可选,初始化
    ↓
main():必需,策略主逻辑
    ↓
exit():可选,退出清理,只执行一次
    ↓
进程结束 → 托管端释放资源 → 上报最终状态

三个回调均为无参数的同步函数。init() 中退出或发生未处理异常时,跳过 main(),仍调用 exit()。因此清理函数必须兼容只完成部分初始化的情况。

情况清理行为最终状态
main() 正常返回执行 exit()STOPPED
Exit() / Exit(code=0)先展开调用栈,再执行 exit()STOPPED
Exit(code=1) 等非零退出码执行 exit()ERROR
用户点击停止主逻辑响应停止请求,等待 exit() 完成清理成功后 STOPPED
未处理异常逃逸出 init() / main()记录异常并执行 exit()ERROR
exit() 自身抛出异常记录清理失败,不重试回调ERROR
脚本无法加载或回调校验失败生命周期尚未建立,不调用 exit()ERROR

加载阶段直接调用 Exit() 会结束加载并上报退出码、原因,但尚未建立清理回调。需要清理的初始化逻辑应放在 init() 内,而非模块顶层。

策略自身已有的 try/finally 先执行,随后框架调用 exit();同一资源的关闭操作应幂等,或只放在一个位置。已有主循环的异常日志/继续运行机制不变:被捕获的异常不会自动结束策略。

停止与等待

  • Python 的正常停止通过托管端控制通道请求退出,不直接杀进程。
  • 清理期间仍保留交易接口、日志与状态服务,允许 exit() 撤单、保存数据、关闭连接。
  • 没有原先的 5 秒强杀超时。 如果 exit() 一直不返回,正常停止就一直等待;不会提前上报 STOPPED。
  • 重复停止不会重入回调。在退出清理期间再次调用 Exit() 不会打断清理,也不会覆盖第一次退出请求。
  • Python 策略的 while / for 循环及 Sleep() 包含协作式取消检查。正在执行的第三方阻塞调用需要先返回;请设置网络、线程等待等操作的超时,避免无限阻塞。
  • exit() 内的 Sleep() 仍按正常时长等待,不会因停止标记而跳过。
  • 用户创建的线程和连接应由清理回调主动停止、关闭并等待完成。框架不会安全地“强杀”某个 Python 工作线程。
  • 系统强杀、崩溃、断电等不可恢复事件无法保证回调执行;不要使用 os._exit() 绕过清理。

最终状态由托管端在策略进程实际结束、资源清理后,通过已有状态上报通道发送。成功退出使用 STOPPED,不新增服务器状态枚举;非零退出或清理失败使用 ERROR。退出原因和退出码放入状态消息。网络不可用时会明确记录上报失败,不把日志输出等同于服务器已收到。

完整示例

python
ws = None


def init():
    global ws
    ws = Dial("wss://fstream.binance.com/ws/btcusdt@depth",
              timeout=10000, auto_reconnect=True)
    if ws is None:
        Exit(code=1, reason="行情连接失败")
    Log("初始化完成")


def main():
    while True:
        command = GetCommand()
        if command == "stop":
            Exit(reason="收到停止指令")
        message = ws.read(250)
        if message:
            LogStatus(message)
        Sleep(100)


def exit():
    global ws
    Log("开始清理")
    try:
        _G("last_exit_time", Unix())
    finally:
        if ws is not None:
            ws.close()
            ws = None
    Log("清理完成")

旧接口迁移

原先注入的 exit(reason) 主动停止方法已移除,不再调用废弃的停止管理接口。

python
# 旧调用 exit("达到目标") 应改成:
Exit(reason="达到目标")

# 清理逻辑定义为小写 exit,由框架调用:
def exit():
    Log("退出清理")

不要直接调用小写 exit() 来请求停止;它只是你的普通清理函数。已有仅定义 init() / main() 的策略仍可运行,不强制要求新增清理回调。

相关方法