refactor QMT client and optimize API
This commit is contained in:
@@ -2,23 +2,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging as log
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import config
|
||||
from dataclasses import dataclass
|
||||
import yaml
|
||||
import httpx
|
||||
|
||||
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||
GLOBAL_CONFIG_PATH = os.path.join(PROJECT_ROOT, "etc", "_global.yaml")
|
||||
if PROJECT_ROOT not in sys.path:
|
||||
sys.path.insert(0, PROJECT_ROOT)
|
||||
|
||||
from sdk import Client
|
||||
from sdk import APIError, Client
|
||||
from strategy.trend.boot import StartTrend
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class StrategyDefinition:
|
||||
mutex_scope: str
|
||||
start_strategy: object
|
||||
@@ -56,24 +58,47 @@ def check_single_instance(project_root: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def ping_api_host(
|
||||
rpc_host: str,
|
||||
retry_interval: float = 5.0,
|
||||
connect_timeout: float = 3.0,
|
||||
) -> None:
|
||||
def wait_for_qmt_api(retry_interval: float = 5.0) -> None:
|
||||
"""循环检查 API 地址,连通后才返回。"""
|
||||
client = Client(config.global_config.qmt_base_url, config.global_config.qmt_token, config.HTTP_TIMEOUT)
|
||||
|
||||
while True:
|
||||
retry_event = __import__("threading").Event()
|
||||
while not retry_event.is_set():
|
||||
try:
|
||||
assets = client.assets()
|
||||
client.assets()
|
||||
log.info(f"API 服务已连通:{config.global_config.qmt_base_url}")
|
||||
client.close()
|
||||
return
|
||||
except:
|
||||
except (APIError, httpx.RequestError) as exc:
|
||||
log.warning(
|
||||
f"API 服务未就绪:{config.global_config.qmt_base_url},{retry_interval:g} 秒后重试"
|
||||
"API 服务未就绪:%s,%g 秒后重试:%s",
|
||||
config.global_config.qmt_base_url,
|
||||
retry_interval,
|
||||
exc,
|
||||
)
|
||||
time.sleep(retry_interval)
|
||||
retry_event.wait(retry_interval)
|
||||
|
||||
|
||||
def configure_logging(data_dir: str) -> None:
|
||||
"""同时输出控制台日志和按天轮转的文本日志。"""
|
||||
log_dir = os.path.join(data_dir, "logs")
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
root = log.getLogger()
|
||||
root.setLevel(log.INFO)
|
||||
formatter = log.Formatter("%(asctime)s [%(levelname)s] %(message)s")
|
||||
if not root.handlers:
|
||||
console = log.StreamHandler()
|
||||
console.setFormatter(formatter)
|
||||
root.addHandler(console)
|
||||
file_handler = TimedRotatingFileHandler(
|
||||
os.path.join(log_dir, "py-client.log"),
|
||||
when="midnight",
|
||||
interval=1,
|
||||
backupCount=30,
|
||||
encoding="utf-8",
|
||||
)
|
||||
file_handler.setFormatter(formatter)
|
||||
root.addHandler(file_handler)
|
||||
|
||||
def wait_for_any_key() -> None:
|
||||
print("按任意键退出...", flush=True)
|
||||
@@ -96,12 +121,12 @@ def main() -> int:
|
||||
config.load()
|
||||
if config.global_config is None or config.account_config is None:
|
||||
raise RuntimeError("配置尚未加载,请先调用 config.load()")
|
||||
|
||||
ping_api_host(config.global_config.qmt_base_url)
|
||||
configure_logging(config.global_config.qmt_data_dir)
|
||||
wait_for_qmt_api()
|
||||
|
||||
STRATEGIES[config.account_config.strategy].start_strategy()
|
||||
return 0
|
||||
except (OSError, yaml.YAMLError, ValueError) as exc:
|
||||
except (OSError, yaml.YAMLError, ValueError, RuntimeError, KeyError) as exc:
|
||||
print(f"启动失败: {exc}", file=sys.stderr, flush=True)
|
||||
wait_for_any_key()
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user