Files
easy-tdx/src/easy_tdx/config.py
T
GitHubandClaude Opus 4.8 4dfd18050e fix: resolve all CI mypy (265→0) and ruff (26→0) errors
- pyproject.toml: add mypy overrides for pandas/tabulate/matplotlib stubs,
  disable strict checking for vendored MyTT library
- config.py: use cast() for dict[str, Any] .get() returns
- beichi.py: widen _calc_bi_force param to BI | XD, import XD
- backtest/cli.py: split combo/single strategy into separate typed variables
- backtest/combo.py: add bool_array() helper for numpy return types
- chanlun/analyser.py: type ignore for pandas row access, fix dict type arg
- unified.py: change fields param from object to Any
- ex/mac_client.py: add type args to list literals
- cli/cmd_offline.py: wrap int market as Market enum before API call
- cli/cmd_chanlun.py: fix dict type arg
- offline/write_*.py: explicit int() cast for struct.unpack returns
- MyTT.py: fix line-too-long comments, UP038 isinstance syntax
- tests: fix E712 (==False → ~mask), E741 (noqa), F841, import sorting
- ruff format applied across codebase

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 15:03:41 +08:00

281 lines
7.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""集中管理服务器地址、端口、超时等配置。
优先级:环境变量 > ~/.easy_tdx/config.json > 源码内嵌默认值。
配置文件示例::
{
"best_host": "180.153.18.170",
"best_host_updated_at": "2026-05-22T10:30:00",
"known_hosts": ["111.229.247.189", ...],
"calc_hosts": ["120.76.152.87"],
"mac_hosts": ["121.36.248.138", ...],
"port": 7709,
"timeout": 15.0
}
环境变量覆盖::
EASY_TDX_HOST -- 单台主机地址
EASY_TDX_PORT -- 端口
EASY_TDX_TIMEOUT -- 超时秒数
EASY_TDX_KNOWN_HOSTS -- 逗号分隔的候选主机列表
EASY_TDX_CONFIG_DIR -- 配置文件目录(默认 ~/.easy_tdx
"""
import json
import os
from datetime import datetime
from pathlib import Path
from typing import Any, cast
_CONFIG_DIR = Path(os.environ.get("EASY_TDX_CONFIG_DIR", str(Path.home() / ".easy_tdx")))
_CONFIG_FILE = _CONFIG_DIR / "config.json"
# ---------------------------------------------------------------------------
# 源码内嵌默认值(config.json 不存在或字段缺失时的兜底)
# ---------------------------------------------------------------------------
_FALLBACK_HOSTS: list[str] = [
"111.229.247.189",
"150.158.160.2",
"180.153.18.170",
"124.71.187.122",
"180.153.18.171",
"180.153.18.172",
"119.147.212.81",
"115.238.56.198",
"115.238.90.165",
"218.75.126.9",
"47.107.75.159",
"59.175.238.38",
"110.41.147.114",
"110.41.2.72",
"101.33.225.16",
"175.178.112.197",
"175.178.128.227",
"43.139.95.83",
"124.223.163.242",
"122.51.120.217",
"123.60.164.122",
"124.70.199.56",
"62.234.50.143",
"81.70.151.186",
"82.156.214.79",
"159.75.29.111",
"43.139.18.171",
"81.71.32.47",
"122.51.232.182",
"118.25.98.114",
"121.36.225.169",
"123.60.70.228",
"123.60.73.44",
"124.70.133.119",
"124.71.187.72",
"119.97.185.59",
"129.204.230.128",
"101.42.240.54",
"124.71.9.153",
"123.60.84.66",
"111.230.186.52",
"101.43.159.194",
"120.53.8.251",
"152.136.191.169",
"116.205.163.254",
"116.205.171.132",
"116.205.183.150",
"49.232.15.141",
"82.156.174.84",
"101.42.164.241",
"101.35.121.35",
"111.231.113.208",
]
_FALLBACK_CALC_HOSTS: list[str] = [
"120.76.152.87",
]
_FALLBACK_MAC_HOSTS: list[str] = [
"121.36.248.138",
"123.60.47.136",
"121.37.207.165",
]
_FALLBACK_EX_HOSTS: list[str] = [
"112.74.214.43",
"120.25.218.6",
"43.139.173.246",
"159.75.90.107",
"106.52.170.195",
"139.9.191.175",
"175.24.47.69",
"150.158.9.199",
"150.158.20.127",
"49.235.119.116",
"49.234.13.160",
"116.205.143.214",
"124.71.223.19",
"113.45.175.47",
"123.60.173.210",
"118.89.69.202",
]
_FALLBACK_MAC_EX_HOSTS: list[str] = [
"116.205.135.205",
"121.37.232.167",
]
_FALLBACK_PORT = 7709
_FALLBACK_TIMEOUT = 15.0
# ---------------------------------------------------------------------------
# 内部读写
# ---------------------------------------------------------------------------
def _load() -> dict[str, Any]:
try:
if _CONFIG_FILE.exists():
return cast(dict[str, Any], json.loads(_CONFIG_FILE.read_text("utf-8")))
except Exception:
pass
return {}
def _save(data: dict[str, Any]) -> None:
_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
tmp = _CONFIG_FILE.with_suffix(".tmp")
tmp.write_text(json.dumps(data, indent=2, ensure_ascii=False), "utf-8")
tmp.replace(_CONFIG_FILE)
# ---------------------------------------------------------------------------
# 公开 getter
# ---------------------------------------------------------------------------
def get_best_host() -> str:
"""返回当前最佳主机地址。优先级:环境变量 > config.json > 默认列表首个。"""
env = os.environ.get("EASY_TDX_HOST")
if env:
return env
cfg = _load()
return cast(str, cfg.get("best_host", _FALLBACK_HOSTS[0]))
def get_known_hosts() -> list[str]:
"""返回候选行情主机列表。"""
env = os.environ.get("EASY_TDX_KNOWN_HOSTS")
if env:
return [h.strip() for h in env.split(",") if h.strip()]
cfg = _load()
return cast(list[str], cfg.get("known_hosts", list(_FALLBACK_HOSTS)))
def get_calc_hosts() -> list[str]:
"""返回计算服务器列表。"""
cfg = _load()
return cast(list[str], cfg.get("calc_hosts", list(_FALLBACK_CALC_HOSTS)))
def get_mac_hosts() -> list[str]:
"""返回 MAC 行情服务器列表。"""
cfg = _load()
return cast(list[str], cfg.get("mac_hosts", list(_FALLBACK_MAC_HOSTS)))
def get_ex_hosts() -> list[str]:
"""返回扩展行情服务器列表。"""
cfg = _load()
return cast(list[str], cfg.get("ex_hosts", list(_FALLBACK_EX_HOSTS)))
def get_best_ex_host() -> str:
"""返回当前最佳扩展行情主机。"""
env = os.environ.get("EASY_TDX_EX_HOST")
if env:
return env
cfg = _load()
return cast(str, cfg.get("best_ex_host", _FALLBACK_EX_HOSTS[0]))
def get_mac_ex_hosts() -> list[str]:
"""返回 MAC 协议扩展行情服务器列表。"""
cfg = _load()
return cast(list[str], cfg.get("mac_ex_hosts", list(_FALLBACK_MAC_EX_HOSTS)))
def get_best_mac_ex_host() -> str:
"""返回当前最佳 MAC 协议扩展行情主机。"""
env = os.environ.get("EASY_TDX_MAC_EX_HOST")
if env:
return env
cfg = _load()
return cast(str, cfg.get("best_mac_ex_host", _FALLBACK_MAC_EX_HOSTS[0]))
def get_port() -> int:
"""返回默认端口。"""
env = os.environ.get("EASY_TDX_PORT")
if env:
return int(env)
cfg = _load()
return cast(int, cfg.get("port", _FALLBACK_PORT))
def get_timeout() -> float:
"""返回默认超时秒数。"""
env = os.environ.get("EASY_TDX_TIMEOUT")
if env:
return float(env)
cfg = _load()
return cast(float, cfg.get("timeout", _FALLBACK_TIMEOUT))
# ---------------------------------------------------------------------------
# 持久化
# ---------------------------------------------------------------------------
def save_best_host(host: str) -> None:
"""保存最佳主机到配置文件;首次写入时同时补全默认配置。"""
cfg = _load()
cfg["best_host"] = host
cfg["best_host_updated_at"] = datetime.now().isoformat()
if "known_hosts" not in cfg:
cfg["known_hosts"] = list(_FALLBACK_HOSTS)
if "calc_hosts" not in cfg:
cfg["calc_hosts"] = list(_FALLBACK_CALC_HOSTS)
if "mac_hosts" not in cfg:
cfg["mac_hosts"] = list(_FALLBACK_MAC_HOSTS)
if "port" not in cfg:
cfg["port"] = _FALLBACK_PORT
if "ex_hosts" not in cfg:
cfg["ex_hosts"] = list(_FALLBACK_EX_HOSTS)
if "mac_ex_hosts" not in cfg:
cfg["mac_ex_hosts"] = list(_FALLBACK_MAC_EX_HOSTS)
_save(cfg)
def save_best_ex_host(host: str) -> None:
"""保存最佳扩展行情主机到配置文件。"""
cfg = _load()
cfg["best_ex_host"] = host
cfg["best_ex_host_updated_at"] = datetime.now().isoformat()
if "ex_hosts" not in cfg:
cfg["ex_hosts"] = list(_FALLBACK_EX_HOSTS)
if "mac_ex_hosts" not in cfg:
cfg["mac_ex_hosts"] = list(_FALLBACK_MAC_EX_HOSTS)
_save(cfg)
def save_best_mac_ex_host(host: str) -> None:
"""保存最佳 MAC 协议扩展行情主机到配置文件。"""
cfg = _load()
cfg["best_mac_ex_host"] = host
cfg["best_mac_ex_host_updated_at"] = datetime.now().isoformat()
if "mac_ex_hosts" not in cfg:
cfg["mac_ex_hosts"] = list(_FALLBACK_MAC_EX_HOSTS)
_save(cfg)