fix: CTP 需 zh_CN.GB18030 中文 locale 而非仅 UTF-8
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -27,10 +27,13 @@ need_install python3-venv python3-venv
|
|||||||
need_install git git
|
need_install git git
|
||||||
|
|
||||||
# vnpy_ctp 在 Linux 上需本地编译(Meson + pkg-config 查找 python3-dev)
|
# vnpy_ctp 在 Linux 上需本地编译(Meson + pkg-config 查找 python3-dev)
|
||||||
echo "==> 安装 vnpy_ctp 编译依赖..."
|
echo "==> 安装 vnpy_ctp 编译依赖与 CTP 中文 locale..."
|
||||||
apt-get install -y build-essential python3-dev pkg-config locales
|
apt-get install -y build-essential python3-dev pkg-config locales
|
||||||
locale-gen en_US.UTF-8 C.UTF-8 2>/dev/null || true
|
# CTP C++ API 登录回调需要 zh_CN.GB18030(vnpy/vnpy_ctp#24)
|
||||||
update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 2>/dev/null || true
|
sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen 2>/dev/null || true
|
||||||
|
sed -i '/^# zh_CN.UTF-8/s/^# //' /etc/locale.gen 2>/dev/null || true
|
||||||
|
locale-gen zh_CN.GB18030 zh_CN.UTF-8 en_US.UTF-8 2>/dev/null || locale-gen
|
||||||
|
update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 2>/dev/null || true
|
||||||
|
|
||||||
if ! command -v pm2 &>/dev/null; then
|
if ! command -v pm2 &>/dev/null; then
|
||||||
echo "==> 安装 PM2..."
|
echo "==> 安装 PM2..."
|
||||||
|
|||||||
+1
-1
@@ -346,7 +346,7 @@ pm2 restart qihuo
|
|||||||
|-----------|------|
|
|-----------|------|
|
||||||
| `pip install vnpy_ctp` 编译失败 / `Python dependency not found` | 安装 `build-essential python3-dev pkg-config` 后重试 |
|
| `pip install vnpy_ctp` 编译失败 / `Python dependency not found` | 安装 `build-essential python3-dev pkg-config` 后重试 |
|
||||||
| CTP 连接超时 | 检查前置 IP、端口、SimNow 是否维护、是否在允许连接时段 |
|
| CTP 连接超时 | 检查前置 IP、端口、SimNow 是否维护、是否在允许连接时段 |
|
||||||
| 连接后立即崩溃 `locale::facet::_S_create_c_locale` | 安装 locale:`apt install -y locales && locale-gen en_US.UTF-8`,`git pull` 后 `pm2 restart qihuo --update-env` |
|
| 连接后立即崩溃 `locale::facet::_S_create_c_locale` | CTP 需 **zh_CN.GB18030**:`sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen && locale-gen zh_CN.GB18030`,再 `pm2 restart qihuo --update-env` |
|
||||||
| 服务器 `180.168.146.187` 超时 | 换 SimNow 备用前置 `182.254.243.31:30001/30011`(见 [SIMNOW.md](./SIMNOW.md)) |
|
| 服务器 `180.168.146.187` 超时 | 换 SimNow 备用前置 `182.254.243.31:30001/30011`(见 [SIMNOW.md](./SIMNOW.md)) |
|
||||||
| 已连接但下单拒单 | 检查合约代码、价格精度、是否有足够保证金 |
|
| 已连接但下单拒单 | 检查合约代码、价格精度、是否有足够保证金 |
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -183,7 +183,7 @@ python scripts/test_simnow.py
|
|||||||
| 报错 **4097** / 握手失败 | `pip install -U vnpy vnpy_ctp`,`.env` 设 `SIMNOW_ENV=实盘` |
|
| 报错 **4097** / 握手失败 | `pip install -U vnpy vnpy_ctp`,`.env` 设 `SIMNOW_ENV=实盘` |
|
||||||
| **不合法的登录** | 投资者代码/密码错,或未在快期改过一次密码 |
|
| **不合法的登录** | 投资者代码/密码错,或未在快期改过一次密码 |
|
||||||
| 快期能登、脚本不能 | 多为网络或前置地址,换 SimNow 官网其他组前置试 |
|
| 快期能登、脚本不能 | 多为网络或前置地址,换 SimNow 官网其他组前置试 |
|
||||||
| 连上后进程崩溃 `locale::facet::_S_create_c_locale` | `apt install -y locales && locale-gen en_US.UTF-8`,`git pull` 后 `pm2 restart qihuo --update-env` |
|
| 连上后进程崩溃 `locale::facet::_S_create_c_locale` | **必须**安装 `zh_CN.GB18030`:`sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen && locale-gen zh_CN.GB18030` |
|
||||||
|
|
||||||
### 提示「未安装 vnpy / vnpy_ctp」
|
### 提示「未安装 vnpy / vnpy_ctp」
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ module.exports = {
|
|||||||
max_memory_restart: "300M",
|
max_memory_restart: "300M",
|
||||||
env: {
|
env: {
|
||||||
NODE_ENV: "production",
|
NODE_ENV: "production",
|
||||||
LANG: "en_US.UTF-8",
|
LANG: "zh_CN.UTF-8",
|
||||||
LC_ALL: "en_US.UTF-8",
|
LC_ALL: "zh_CN.UTF-8",
|
||||||
LC_CTYPE: "en_US.UTF-8",
|
LC_CTYPE: "zh_CN.UTF-8",
|
||||||
},
|
},
|
||||||
error_file: "/opt/qihuo/logs/pm2-error.log",
|
error_file: "/opt/qihuo/logs/pm2-error.log",
|
||||||
out_file: "/opt/qihuo/logs/pm2-out.log",
|
out_file: "/opt/qihuo/logs/pm2-out.log",
|
||||||
|
|||||||
+39
-13
@@ -11,29 +11,48 @@ logger = logging.getLogger(__name__)
|
|||||||
_LOCALE_DONE = False
|
_LOCALE_DONE = False
|
||||||
_LOCALE_NAME = ""
|
_LOCALE_NAME = ""
|
||||||
|
|
||||||
|
# CTP C++ API 登录回调依赖中文 locale(见 vnpy/vnpy_ctp#24)
|
||||||
|
_CTP_REQUIRED_LOCALES = ("zh_CN.GB18030", "zh_CN.gb18030")
|
||||||
|
|
||||||
|
|
||||||
|
def _available_locales() -> set[str]:
|
||||||
|
try:
|
||||||
|
out = subprocess.check_output(["locale", "-a"], text=True, stderr=subprocess.DEVNULL)
|
||||||
|
return {line.strip() for line in out.splitlines() if line.strip()}
|
||||||
|
except (OSError, subprocess.SubprocessError):
|
||||||
|
return set()
|
||||||
|
|
||||||
|
|
||||||
|
def missing_ctp_locales() -> list[str]:
|
||||||
|
"""CTP 所需的 zh_CN.GB18030 是否已安装。"""
|
||||||
|
avail = {x.lower() for x in _available_locales()}
|
||||||
|
if any(x.lower() in avail for x in _CTP_REQUIRED_LOCALES):
|
||||||
|
return []
|
||||||
|
return ["zh_CN.GB18030"]
|
||||||
|
|
||||||
|
|
||||||
def _list_locale_candidates() -> list[str]:
|
def _list_locale_candidates() -> list[str]:
|
||||||
|
avail = _available_locales()
|
||||||
names: list[str] = []
|
names: list[str] = []
|
||||||
|
# CTP 回调优先尝试中文 locale
|
||||||
for item in (
|
for item in (
|
||||||
"C.UTF-8",
|
"zh_CN.GB18030",
|
||||||
|
"zh_CN.gb18030",
|
||||||
|
"zh_CN.UTF-8",
|
||||||
|
"zh_CN.utf8",
|
||||||
"en_US.UTF-8",
|
"en_US.UTF-8",
|
||||||
"en_US.utf8",
|
"en_US.utf8",
|
||||||
|
"C.UTF-8",
|
||||||
|
"C.utf8",
|
||||||
"POSIX",
|
"POSIX",
|
||||||
"C",
|
"C",
|
||||||
):
|
):
|
||||||
if item not in names:
|
if item in avail and item not in names:
|
||||||
names.append(item)
|
names.append(item)
|
||||||
try:
|
for loc in sorted(avail):
|
||||||
out = subprocess.check_output(["locale", "-a"], text=True, stderr=subprocess.DEVNULL)
|
|
||||||
for line in out.splitlines():
|
|
||||||
loc = line.strip()
|
|
||||||
if not loc:
|
|
||||||
continue
|
|
||||||
low = loc.lower()
|
low = loc.lower()
|
||||||
if "utf" in low and loc not in names:
|
if "utf" in low and loc not in names:
|
||||||
names.insert(0, loc)
|
names.append(loc)
|
||||||
except (OSError, subprocess.SubprocessError):
|
|
||||||
pass
|
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
|
||||||
@@ -43,6 +62,14 @@ def ensure_process_locale() -> str:
|
|||||||
if _LOCALE_DONE:
|
if _LOCALE_DONE:
|
||||||
return _LOCALE_NAME
|
return _LOCALE_NAME
|
||||||
|
|
||||||
|
missing = missing_ctp_locales()
|
||||||
|
if missing:
|
||||||
|
raise RuntimeError(
|
||||||
|
"CTP 需要中文 locale zh_CN.GB18030,当前系统未安装。"
|
||||||
|
"请执行: sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen && "
|
||||||
|
"locale-gen zh_CN.GB18030"
|
||||||
|
)
|
||||||
|
|
||||||
last_err: locale.Error | None = None
|
last_err: locale.Error | None = None
|
||||||
for name in _list_locale_candidates():
|
for name in _list_locale_candidates():
|
||||||
try:
|
try:
|
||||||
@@ -60,6 +87,5 @@ def ensure_process_locale() -> str:
|
|||||||
|
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"未找到可用 locale,vnpy_ctp 会在 CTP 登录后崩溃。"
|
"未找到可用 locale,vnpy_ctp 会在 CTP 登录后崩溃。"
|
||||||
"请执行: apt install -y locales && locale-gen en_US.UTF-8 && "
|
"请执行: apt install -y locales && locale-gen zh_CN.GB18030 en_US.UTF-8"
|
||||||
"update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8"
|
|
||||||
) from last_err
|
) from last_err
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import sys
|
|||||||
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
sys.path.insert(0, BASE)
|
sys.path.insert(0, BASE)
|
||||||
|
|
||||||
from locale_fix import ensure_process_locale
|
from locale_fix import ensure_process_locale, missing_ctp_locales
|
||||||
|
|
||||||
ensure_process_locale()
|
ensure_process_locale()
|
||||||
|
|
||||||
@@ -40,6 +40,9 @@ def main() -> int:
|
|||||||
|
|
||||||
print("=== SimNow 配置 ===")
|
print("=== SimNow 配置 ===")
|
||||||
print(f"locale = {ensure_process_locale()}")
|
print(f"locale = {ensure_process_locale()}")
|
||||||
|
missing = missing_ctp_locales()
|
||||||
|
if missing:
|
||||||
|
print(f"警告: 缺少 CTP 所需 locale: {', '.join(missing)}")
|
||||||
print(f"SIMNOW_USER = {user or '(未设置)'}")
|
print(f"SIMNOW_USER = {user or '(未设置)'}")
|
||||||
print(f"SIMNOW_PASSWORD = {'*' * 8 if os.getenv('SIMNOW_PASSWORD') else '(未设置)'}")
|
print(f"SIMNOW_PASSWORD = {'*' * 8 if os.getenv('SIMNOW_PASSWORD') else '(未设置)'}")
|
||||||
print(f"SIMNOW_TD = {td}")
|
print(f"SIMNOW_TD = {td}")
|
||||||
|
|||||||
Reference in New Issue
Block a user