一键导入
install-opend
OpenD 安装助手。自动下载安装富途/moomoo OpenD 并升级 Python SDK。支持 Windows、MacOS、Linux。用户提到安装、下载、启动、运行、配置 OpenD、开发环境、升级 SDK、futu-api 时自动使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
OpenD 安装助手。自动下载安装富途/moomoo OpenD 并升级 Python SDK。支持 Windows、MacOS、Linux。用户提到安装、下载、启动、运行、配置 OpenD、开发环境、升级 SDK、futu-api 时自动使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Baostock 历史K线数据使用规范。所有历史K线数据必须使用 baostock 获取,不允许使用 futu、akshare 或其他数据源。用户提到 K线、历史数据、复权数据、get_kline、history_k_line 时自动使用。
富途/moomoo OpenAPI 交易与行情助手。查询股票行情、K线、报价、快照、买卖盘、逐笔成交、分时数据;解析期权简写代码、查询期权链、期权到期日;执行买入/卖出/下单/撤单/改单;查询持仓/资金/账户/订单;订阅实时推送;API 接口速查。用户提到行情、报价、价格、K线、快照、买卖盘、摆盘、成交、分时、买入、卖出、下单、撤单、交易、持仓、资金、账户、订单、委托、futu、moomoo、OpenAPI、选股、板块、期权、期权链、期权代码、行权价、到期日、Call、Put、看涨、看跌、认购、认沽 时自动使用。
Use when editing or running this repository on Windows, especially if the task touches Chinese text, console output, logs, HTML templates, or any file that may show garbled characters. Helps prevent and fix UTF-8/GBK mojibake in this project.
| name | install-opend |
| description | OpenD 安装助手。自动下载安装富途/moomoo OpenD 并升级 Python SDK。支持 Windows、MacOS、Linux。用户提到安装、下载、启动、运行、配置 OpenD、开发环境、升级 SDK、futu-api 时自动使用。 |
| allowed-tools | Bash Read Write Edit WebFetch |
你是富途/moomoo OpenAPI 安装助手,自动下载安装 OpenD 并升级 SDK。默认安装富途版,可通过参数指定 moomoo 版。
根据用户输入的语言自动回复。用户使用英文提问则用英文回复,使用中文提问则用中文回复,其他语言同理。语言不明确时默认使用中文。技术术语(如代码、API 名称、命令行参数)保持原文不翻译。
支持通过 $ARGUMENTS 传入以下参数:
| 参数 | 说明 | 示例 |
|---|---|---|
mm / moomoo | 安装 moomoo 版 | /install-opend moomoo |
nn / 牛牛 / futu | 安装富途(牛牛)版(默认) | /install-opend nn |
-path 路径 | 指定下载保存路径 | /install-opend -path D:\Downloads |
可组合使用:/install-opend moomoo -path C:\Users\me\Desktop
解析规则:
mm 或 moomoo → 品牌 = moomoonn / 牛牛 / futu 或未指定品牌 → 品牌 = 富途(默认)-path xxx → 下载路径 = xxx(取 -path 后面的路径字符串)-path → 默认下载到桌面,不询问,直接提示"安装包将下载到桌面"skill 启动后,第一步根据 $ARGUMENTS 确定品牌:
mm 或 moomoo → 品牌 = moomoonn / 牛牛 / futu 或未指定) → 品牌 = 富途(默认)品牌确定后输出提示:
将安装{富途/moomoo} OpenD,安装包将默认下载到桌面。如需指定路径,可使用
/install-opend -path D:\Downloads
确定品牌后,第二步通过 Bash 工具自动检测当前操作系统:
uname -s 2>/dev/null || echo Windows
根据输出判断:
MINGW、MSYS、CYGWIN 或命令失败 → WindowsDarwin → MacOSLinux → 需进一步判断发行版:cat /etc/os-release 2>/dev/null | head -5
CentOS → CentOSUbuntu → Ubuntu将检测结果记录为变量 detected_os,用于后续选择下载链接。
检测完成后输出提示:
检测到系统: {detected_os} | 品牌: {nn/mm} | 下载路径: {桌面/自定义路径},开始下载...
根据检测和选择结果:
detected_os → 决定下载哪个平台的安装包,以及后续安装指引-path 参数,默认桌面) → 决定保存位置用户选择 moomoo 时使用 moomoo 品牌的下载地址和配置说明。 默认使用富途(牛牛)品牌。
| 平台 | 下载链接 |
|---|---|
| Windows | https://www.futunn.com/download/fetch-lasted-link?name=opend-windows |
| MacOS | https://www.futunn.com/download/fetch-lasted-link?name=opend-macos |
| CentOS | https://www.futunn.com/download/fetch-lasted-link?name=opend-centos |
| Ubuntu | https://www.futunn.com/download/fetch-lasted-link?name=opend-ubuntu |
以上链接自动获取最新版本。
| 平台 | 下载链接 |
|---|---|
| Windows | https://www.moomoo.com/download/fetch-lasted-link?name=opend-windows |
| MacOS | https://www.moomoo.com/download/fetch-lasted-link?name=opend-macos |
| CentOS | https://www.moomoo.com/download/fetch-lasted-link?name=opend-centos |
| Ubuntu | https://www.moomoo.com/download/fetch-lasted-link?name=opend-ubuntu |
网页下载页面:https://www.moomoo.com/download/OpenAPI
moomoo 的 fetch-lasted-link API 可能不支持 opend-* 参数(返回 400 错误或无重定向)。当上述 moomoo 版下载链接失败时,使用以下 fallback 方式:
fetch-lasted-link API 获取最新版本号(两个品牌版本号一致)softwaredownload.moomoo.com 的直接下载 URL文件名命名规则(将富途版文件名中的 Futu 替换为 moomoo):
| 平台 | 直接下载 URL 模板 |
|---|---|
| Windows | https://softwaredownload.moomoo.com/moomoo_OpenD_{VERSION}_Windows.7z |
| MacOS | https://softwaredownload.moomoo.com/moomoo_OpenD_{VERSION}_Mac.tar.gz |
| CentOS | https://softwaredownload.moomoo.com/moomoo_OpenD_{VERSION}_CentOS.tar.gz |
| Ubuntu | https://softwaredownload.moomoo.com/moomoo_OpenD_{VERSION}_Ubuntu.tar.gz |
其中 {VERSION} 替换为从富途版 API 获取的最新版本号(如 10.0.6018)。
Fallback 获取版本号的方法:
macOS / Linux:
LATEST_URL=$(curl -sI "https://www.futunn.com/download/fetch-lasted-link?name=opend-{platform}" | grep -i "^location:" | awk '{print $2}' | tr -d '\r')
LATEST_VER=$(echo "$LATEST_URL" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
MOOMOO_URL="https://softwaredownload.moomoo.com/moomoo_OpenD_${LATEST_VER}_{Platform}.tar.gz"
Windows(PowerShell):
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$request = [System.Net.HttpWebRequest]::Create("https://www.futunn.com/download/fetch-lasted-link?name=opend-windows")
$request.AllowAutoRedirect = $true
$response = $request.GetResponse()
$finalUrl = $response.ResponseUri.ToString()
$response.Close()
if ($finalUrl -match '(\d+\.\d+\.\d+)') { $latestVer = $Matches[1] }
$moomooUrl = "https://softwaredownload.moomoo.com/moomoo_OpenD_${latestVer}_Windows.7z"
| 特性 | GUI 版(可视化 OpenD) | 命令行版 |
|---|---|---|
| 界面 | 图形界面,操作便捷 | 无界面,命令行操作 |
| 适合人群 | 入门用户,快速上手 | 熟悉命令行、服务器挂机 |
| 配置方式 | 界面右侧直接配置 | 编辑 XML 配置文件 |
| WebSocket | 默认启用 | 需手动配置开启 |
| 安装方式 | 一键安装 | 解压即用 |
必须安装 GUI 版,禁止启动命令行版 OpenD。命令行版(FutuOpenD / FutuOpenD.exe,无下划线)不得运行,所有平台(Windows、macOS、Linux)统一使用 GUI 版(Futu_OpenD,带下划线)。
检测到操作系统后、开始下载前,自动检测本地是否已安装 OpenD,并与线上最新版本对比。如果本地版本 ≥ 最新版本,提示已安装最新版本并跳过下载安装步骤。
通过 fetch-lasted-link API 的重定向 URL 提取最新版本号({platform} 根据 detected_os 替换为 windows、macos、centos 或 ubuntu)。
moomoo 版注意:moomoo 的 fetch-lasted-link API 可能返回 400 错误,此时应使用富途版 API(www.futunn.com)获取版本号,两个品牌版本号一致。
LATEST_URL=$(curl -sI "https://www.futunn.com/download/fetch-lasted-link?name=opend-{platform}" | grep -i "^location:" | awk '{print $2}' | tr -d '\r')
LATEST_VER=$(echo "$LATEST_URL" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
echo "Latest version: $LATEST_VER"
生成 PowerShell 脚本获取(避免 Bash 中 $ 转义问题):
$response = Invoke-WebRequest -Uri "https://www.futunn.com/download/fetch-lasted-link?name=opend-windows" -MaximumRedirection 0 -ErrorAction SilentlyContinue
$redirectUrl = $response.Headers.Location
if ($redirectUrl -match '(\d+\.\d+\.\d+)') { Write-Host "LATEST_VER=$($Matches[1])" }
生成 PowerShell 脚本,依次通过以下方式检测本地已安装版本。必须根据当前安装的品牌选择对应的检测目标:富途版检测 Futu_OpenD,moomoo 版检测 moomoo_OpenD,两者互不干扰。
DisplayVersion(最可靠,GUI 版安装后会写入注册表)注意(仅 Windows):GUI 版可执行文件的 VersionInfo.ProductVersion 为空,不能通过文件属性获取版本号,必须优先从注册表读取。macOS 和 Linux 不受此问题影响。
$localVer = "not_installed"
# === Brand-specific target names ===
# Futu: $targetName = "Futu_OpenD", $processName = "Futu_OpenD", $installDir = "Futu_OpenD"
# moomoo: $targetName = "moomoo_OpenD", $processName = "moomoo_OpenD", $installDir = "moomoo_OpenD"
$targetName = "Futu_OpenD" # moomoo version: "moomoo_OpenD"
$processName = "Futu_OpenD" # moomoo version: "moomoo_OpenD"
$installDir = "Futu_OpenD" # moomoo version: "moomoo_OpenD"
# Method 1: Check registry uninstall entries (most reliable)
# GUI installer writes DisplayVersion to HKCU uninstall registry
$regPaths = @(
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
)
foreach ($regPath in $regPaths) {
if ($localVer -ne "not_installed") { break }
if (-not (Test-Path $regPath)) { continue }
Get-ChildItem -Path $regPath -ErrorAction SilentlyContinue | ForEach-Object {
$props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
if ($props.DisplayName -eq $targetName -and $props.DisplayVersion) {
if ($props.DisplayVersion -match '(\d+\.\d+\.\d+)') {
$localVer = $Matches[1]
}
}
}
}
# Method 2: Check running GUI OpenD process (brand-specific)
if ($localVer -eq "not_installed") {
$proc = Get-Process -Name $processName -ErrorAction SilentlyContinue | Select-Object -First 1
if ($proc -and $proc.Path) {
# ProductVersion may be empty for GUI OpenD, try path-based extraction
if ($proc.Path -match '(\d+\.\d+\.\d+)') {
$localVer = $Matches[1]
}
}
}
# Method 3: Check if GUI OpenD executable exists at default install path (brand-specific)
if ($localVer -eq "not_installed") {
$guiPath = Join-Path $env:APPDATA "$installDir\$processName.exe"
if (Test-Path $guiPath) {
# Executable exists but has no version info embedded; mark as installed with unknown version
# The registry method above should have caught this, but as fallback confirm it's installed
$localVer = "installed_unknown"
}
}
Write-Host "LOCAL_VER=$localVer"
依次通过以下方式检测。必须根据品牌使用对应的名称:富途版用 Futu,moomoo 版用 moomoo,避免交叉匹配。
LOCAL_VER="not_installed"
# === Brand-specific variables ===
# Futu: BRAND_PREFIX="Futu", APP_NAME="Futu OpenD-GUI"
# moomoo: BRAND_PREFIX="moomoo", APP_NAME="moomoo OpenD-GUI"
BRAND_PREFIX="Futu" # moomoo version: "moomoo"
APP_NAME="Futu OpenD-GUI" # moomoo version: "moomoo OpenD-GUI"
# Method 1: Check running brand-specific OpenD process
OPEND_PID=$(pgrep -f "${BRAND_PREFIX}_OpenD" 2>/dev/null | head -1)
if [ -n "$OPEND_PID" ]; then
OPEND_PATH=$(ps -p "$OPEND_PID" -o comm= 2>/dev/null)
if echo "$OPEND_PATH" | grep -qoE '[0-9]+\.[0-9]+\.[0-9]+'; then
LOCAL_VER=$(echo "$OPEND_PATH" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
fi
# Method 2: Read Info.plist from /Applications/ (brand-specific)
if [ "$LOCAL_VER" = "not_installed" ]; then
LOCAL_VER=$(defaults read "/Applications/${APP_NAME}.app/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null || echo "not_installed")
fi
# Method 3: Search common paths, extract version from filename (brand-specific)
if [ "$LOCAL_VER" = "not_installed" ]; then
FOUND=$(find "$HOME/Desktop" /Applications /opt "$HOME/Downloads" -maxdepth 4 -name "${BRAND_PREFIX}*OpenD*GUI*.dmg" -o -name "${BRAND_PREFIX}*OpenD*GUI*.app" 2>/dev/null | head -1)
if [ -n "$FOUND" ] && echo "$FOUND" | grep -qoE '[0-9]+\.[0-9]+\.[0-9]+'; then
LOCAL_VER=$(echo "$FOUND" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
fi
echo "Local version: $LOCAL_VER"
依次通过以下方式检测。必须根据品牌使用对应的名称:富途版用 Futu_OpenD,moomoo 版用 moomoo_OpenD,避免交叉匹配。
注意:Linux 也使用 GUI 版(带下划线),禁止运行命令行版(无下划线)。
LOCAL_VER="not_installed"
# === Brand-specific variables ===
# Futu: BRAND_PROCESS="Futu_OpenD", BRAND_PREFIX="Futu"
# moomoo: BRAND_PROCESS="moomoo_OpenD", BRAND_PREFIX="moomoo"
BRAND_PROCESS="Futu_OpenD" # moomoo version: "moomoo_OpenD"
BRAND_PREFIX="Futu" # moomoo version: "moomoo"
# Method 1: Check running GUI OpenD process (brand-specific)
OPEND_PID=$(pgrep -f "$BRAND_PROCESS" 2>/dev/null | head -1)
if [ -n "$OPEND_PID" ]; then
OPEND_PATH=$(readlink -f /proc/"$OPEND_PID"/exe 2>/dev/null)
if [ -n "$OPEND_PATH" ] && echo "$OPEND_PATH" | grep -qoE '[0-9]+\.[0-9]+\.[0-9]+'; then
LOCAL_VER=$(echo "$OPEND_PATH" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
fi
# Method 2: Search common paths for brand-specific GUI version
if [ "$LOCAL_VER" = "not_installed" ]; then
OPEND_BIN=$(find "$HOME/Desktop" /opt /usr/local "$HOME/Downloads" -maxdepth 4 -name "$BRAND_PROCESS" -type f 2>/dev/null | head -1)
if [ -n "$OPEND_BIN" ] && echo "$OPEND_BIN" | grep -qoE '[0-9]+\.[0-9]+\.[0-9]+'; then
LOCAL_VER=$(echo "$OPEND_BIN" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
fi
# Method 3: Search for brand-specific GUI installer/package by filename
if [ "$LOCAL_VER" = "not_installed" ]; then
FOUND=$(find "$HOME/Desktop" /opt /usr/local "$HOME/Downloads" -maxdepth 4 -name "${BRAND_PREFIX}*OpenD-GUI*" 2>/dev/null | head -1)
if [ -n "$FOUND" ] && echo "$FOUND" | grep -qoE '[0-9]+\.[0-9]+\.[0-9]+'; then
LOCAL_VER=$(echo "$FOUND" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
fi
LOCAL_VER=${LOCAL_VER:-"not_installed"}
echo "Local version: $LOCAL_VER"
版本号格式为 X.Y.ZZZZ(如 10.0.6018),按数值逐段对比。
Bash 对比方法(macOS / Linux):
if [ "$LOCAL_VER" = "not_installed" ]; then
echo "STATUS=not_installed"
elif printf '%s\n' "$LATEST_VER" "$LOCAL_VER" | sort -V | head -1 | grep -qx "$LATEST_VER"; then
echo "STATUS=up_to_date"
else
echo "STATUS=needs_update"
fi
PowerShell 对比方法(Windows):
if ($localVer -eq "not_installed") {
Write-Host "STATUS=not_installed"
} elseif ([version]$localVer -ge [version]$latestVer) {
Write-Host "STATUS=up_to_date"
} else {
Write-Host "STATUS=needs_update"
}
| 情况 | 动作 |
|---|---|
本地未安装(not_installed) | 继续正常下载安装流程 |
本地版本 < 最新版本(needs_update) | 提示"检测到本地 OpenD 版本 {LOCAL_VER},最新版本为 {LATEST_VER},将自动升级",继续下载安装 |
本地版本 ≥ 最新版本(up_to_date) | 提示"本地已安装最新版本的 OpenD({LOCAL_VER}),无需重新安装",跳过下载和安装步骤,直接进入 SDK 升级步骤 |
下载并解压完成后、启动安装程序前,必须验证解压出的安装文件版本与预期下载的最新版本(LATEST_VER)一致,防止 CDN 缓存、下载中断或镜像不同步导致实际安装文件版本不符。
解压后的目录名和安装文件名中均包含版本号(如 Futu_OpenD-GUI_10.1.6117_Windows.exe)。校验方式为:在解压目录中查找文件名包含预期版本号(LATEST_VER)的 GUI 安装程序,找到则校验通过,找不到则校验失败。
注意:压缩包可能同时包含多个版本的目录(如同时包含 10.0.6018 和 10.1.6117),因此不能用 Select-Object -First 1 或 head -1 取第一个匹配再对比版本号,必须直接按预期版本号筛选文件。
在解压完成后、启动安装程序前执行校验。将以下逻辑添加到 PowerShell 脚本的 Step 2(解压)和 Step 3(启动安装程序)之间:
# Step 2.5: Verify expected version exists in extracted files
$guiExe = Get-ChildItem -Path $extractDir -Recurse -Filter "*OpenD-GUI*$latestVer*.exe" | Select-Object -First 1
if ($guiExe) {
Write-Host "Version verified: found $($guiExe.Name) (matches expected $latestVer)"
} else {
# Fallback: list all GUI exe versions found for diagnosis
$allGui = Get-ChildItem -Path $extractDir -Recurse -Filter "*OpenD-GUI*.exe"
$foundVersions = ($allGui | ForEach-Object { if ($_.Name -match '(\d+\.\d+\.\d+)') { $Matches[1] } }) -join ", "
Write-Host "WARNING: Expected version $latestVer not found in extracted files."
Write-Host "Found versions: $foundVersions"
Write-Host "The download may not contain the expected version. Aborting installation."
exit 1
}
注意:$latestVer 需在脚本顶部通过获取重定向 URL 或下载链接文件名提取并传入。校验通过后,后续 Step 3 应使用此处找到的 $guiExe 来启动安装程序。
在解压完成后(第三步)、挂载 DMG 前(第四步)执行校验:
DMG_FILE=$(find "$HOME/Desktop" -maxdepth 3 -name "*OpenD-GUI*${LATEST_VER}*.dmg" -type f | head -1)
if [ -n "$DMG_FILE" ]; then
echo "Version verified: found $(basename "$DMG_FILE") (matches expected $LATEST_VER)"
else
# List all GUI DMG versions found for diagnosis
ALL_DMG=$(find "$HOME/Desktop" -maxdepth 3 -name "*OpenD-GUI*.dmg" -type f 2>/dev/null)
echo "WARNING: Expected version $LATEST_VER not found in extracted files."
echo "Found DMG files: $ALL_DMG"
echo "The download may not contain the expected version. Aborting installation."
exit 1
fi
如果用户通过 -path 指定了路径,将 $HOME/Desktop 替换为对应路径。校验通过后,后续挂载步骤应使用此处找到的 $DMG_FILE。
在解压完成后、安装 GUI 包前执行校验:
# Ubuntu/Debian
PKG_FILE=$(find ~/Desktop -maxdepth 3 \( -name "*OpenD-GUI*${LATEST_VER}*.deb" -o -name "*OpenD-GUI*${LATEST_VER}*.rpm" \) -type f 2>/dev/null | head -1)
# CentOS/RHEL
# PKG_FILE=$(find ~/Desktop -maxdepth 3 -name "*OpenD-GUI*${LATEST_VER}*.rpm" -type f | head -1)
if [ -n "$PKG_FILE" ]; then
echo "Version verified: found $(basename "$PKG_FILE") (matches expected $LATEST_VER)"
else
ALL_PKG=$(find ~/Desktop -maxdepth 3 \( -name "*OpenD-GUI*.deb" -o -name "*OpenD-GUI*.rpm" \) -type f 2>/dev/null)
echo "WARNING: Expected version $LATEST_VER not found in extracted files."
echo "Found packages: $ALL_PKG"
echo "The download may not contain the expected version. Aborting installation."
exit 1
fi
如果用户通过 -path 指定了路径,将 ~/Desktop 替换为对应路径。校验通过后,后续安装步骤应使用此处找到的 $PKG_FILE。
| 情况 | 动作 |
|---|---|
| 找到预期版本文件 | 输出 "Version verified: found xxx",继续安装流程 |
| 未找到预期版本文件 | 输出警告并列出实际找到的版本,中止安装,提示下载内容可能不包含预期版本 |
根据 detected_os 和用户选择的品牌/路径,自动执行下载。
| detected_os | 下载链接 |
|---|---|
| Windows | https://www.futunn.com/download/fetch-lasted-link?name=opend-windows |
| MacOS | https://www.futunn.com/download/fetch-lasted-link?name=opend-macos |
| CentOS | https://www.futunn.com/download/fetch-lasted-link?name=opend-centos |
| Ubuntu | https://www.futunn.com/download/fetch-lasted-link?name=opend-ubuntu |
使用 fetch-lasted-link API 自动获取对应平台的最新版本(与富途版同理,将域名替换为 www.moomoo.com)。如果 moomoo API 返回错误(如 400)或无重定向,则使用 fallback 方式:通过富途版 API 获取版本号,再拼接 softwaredownload.moomoo.com 直接下载 URL。详见上方"moomoo 版 Fallback 下载方式"。
重要:Windows 版安装包是 7z 压缩包,解压后得到的 *OpenD-GUI*.exe 是一个安装程序(非最终可执行程序),启动后会弹出安装向导界面,用户需要按指引完成安装。
压缩包内部结构(以富途为例):
Futu_OpenD_x.x.xxxx_Windows/
├── Futu_OpenD-GUI_x.x.xxxx_Windows/
│ └── Futu_OpenD-GUI_x.x.xxxx_Windows.exe ← GUI 版安装程序(安装后生成 %APPDATA%\Futu_OpenD\Futu_OpenD.exe)
├── Futu_OpenD_x.x.xxxx_Windows/
│ ├── FutuOpenD.exe ← 命令行版主程序(不要启动这个)
│ ├── FutuOpenD.xml ← 配置文件
│ ├── AppData.dat ← 数据文件
│ └── ...(DLL 等依赖)
└── README.txt
重要:Futu_OpenD-GUI*.exe 是 GUI 版的安装程序,安装完成后 GUI 版会安装到 %APPDATA%\Futu_OpenD\Futu_OpenD.exe。Futu_OpenD_x.x.xxxx_Windows/ 目录下的 FutuOpenD.exe 是命令行版,不要启动命令行版。
生成 PowerShell 脚本(install_opend.ps1),一键完成下载、解压、启动安装程序。
启动安装程序后:
重要:PowerShell 脚本中必须使用英文输出。在 MINGW64/Git Bash 环境下通过 powershell -ExecutionPolicy Bypass -File 执行 .ps1 脚本时,如果脚本中包含中文字符(如 Write-Host "正在下载..."),会因编码问题导致 TerminatorExpectedAtEndOfString 解析错误。所有 Write-Host 输出必须使用英文。
# ===== Replace variables based on brand and path =====
$url = "https://www.futunn.com/download/fetch-lasted-link?name=opend-windows"
$downloadDir = [Environment]::GetFolderPath("Desktop") # or user-specified path
$archiveName = "FutuOpenD.7z"
# =====================================================
$archivePath = Join-Path $downloadDir $archiveName
$extractDir = Join-Path $downloadDir "FutuOpenD"
# Step 1: Download
Write-Host "Downloading latest OpenD..."
Invoke-WebRequest -Uri $url -OutFile $archivePath -UseBasicParsing
$size = [math]::Round((Get-Item $archivePath).Length / 1MB, 2)
Write-Host "Download complete! File size: $size MB"
# Step 2: Extract (requires 7-Zip)
$sevenZip = "C:\Program Files\7-Zip\7z.exe"
if (-not (Test-Path $sevenZip)) {
$sevenZip = "C:\Program Files (x86)\7-Zip\7z.exe"
}
if (Test-Path $sevenZip) {
Write-Host "Extracting..."
& $sevenZip x $archivePath -o"$extractDir" -y | Out-Null
Write-Host "Extracted to: $extractDir"
} else {
Write-Host "7-Zip not found. Please extract manually: $archivePath"
Write-Host "Download 7-Zip: https://www.7-zip.org/download.html"
Write-Host "Backup link: https://github.com/ip7z/7zip/releases"
exit 1
}
# Step 3: Launch OpenD installer
$guiExe = Get-ChildItem -Path $extractDir -Recurse -Filter "*OpenD-GUI*.exe" | Select-Object -First 1
if ($guiExe) {
Write-Host "Launching OpenD installer: $($guiExe.FullName)"
Start-Process $guiExe.FullName
Write-Host "Installer launched. Please follow the installation wizard to complete setup."
} else {
Write-Host "Installer not found. Check directory: $extractDir"
}
# Cleanup
Remove-Item $archivePath -Force
Write-Host "Done! Follow the installer to complete installation."
品牌替换规则:
$url 使用 futunn.com 链接,$archiveName = "FutuOpenD.7z"$url 使用 moomoo.com 链接,$archiveName = "MoomooOpenD.7z"路径替换规则:
$downloadDir = [Environment]::GetFolderPath("Desktop")$downloadDir = "用户提供的路径"前置条件:需要安装 7-Zip。如果未安装,脚本会提示,此时告知用户:
https://www.7-zip.org/download.htmlhttps://github.com/ip7z/7zip/releases执行步骤:
install_opend.ps1powershell -ExecutionPolicy Bypass -File "install_opend.ps1"rm install_opend.ps1注意:Bash 工具中 $ 符号会被转义,必须先写 .ps1 文件再执行。
MacOS 版安装包是 tar.gz 压缩包,直接从软件下载服务器获取。
压缩包内部结构(以富途为例):
Futu_OpenD_x.x.xxxx_Mac/
├── Futu_OpenD-GUI_x.x.xxxx_Mac.dmg ← GUI 版安装镜像(需挂载安装)
├── Futu_OpenD_x.x.xxxx_Mac.app ← 命令行版(非 GUI,不要装这个)
├── Futu_OpenD_x.x.xxxx_Mac/
│ ├── FutuOpenD ← 命令行版主程序
│ ├── FutuOpenD.xml ← 配置文件
│ └── ...
├── fixrun.sh ← 路径修复脚本
└── README.txt
重要:.app 是命令行版,.dmg 才是 GUI 版。默认应安装 .dmg(GUI 版)。
安装包约 374MB,下载耗时较长。需要分步执行,每步用独立的 Bash 调用,避免超时。
第一步:获取最新版本文件名
通过 fetch-lasted-link API 的重定向获取最新版本文件名(不要用 WebFetch 访问官方下载页):
# 富途版
curl -sI "https://www.futunn.com/download/fetch-lasted-link?name=opend-macos" | grep -i "^location:" | awk '{print $2}' | tr -d '\r'
# moomoo 版
curl -sI "https://www.moomoo.com/download/fetch-lasted-link?name=opend-macos" | grep -i "^location:" | awk '{print $2}' | tr -d '\r'
从重定向 URL 中提取文件名(如 Futu_OpenD_10.0.6018_Mac.tar.gz 或 moomoo_OpenD_10.0.6018_Mac.tar.gz)。
第二步:从 softwaredownload 域名直接下载
用提取到的文件名拼接 softwaredownload 域名 URL,用 Bash 工具执行下载,必须设置 timeout 为 600000(10 分钟):
https://softwaredownload.futunn.com/{文件名}https://softwaredownload.moomoo.com/{文件名}# 富途版示例
curl -L -o "$HOME/Desktop/FutuOpenD.tar.gz" "https://softwaredownload.futunn.com/Futu_OpenD_10.0.6018_Mac.tar.gz"
# moomoo 版示例
curl -L -o "$HOME/Desktop/MoomooOpenD.tar.gz" "https://softwaredownload.moomoo.com/moomoo_OpenD_10.0.6018_Mac.tar.gz"
其中文件名替换为第一步获取的实际文件名。
路径替换规则:
$HOME/Desktop-path 指定时替换为对应路径下载完成后确认文件大小:
du -h "$HOME/Desktop/FutuOpenD.tar.gz"
第三步:解压
tar -xzf "$HOME/Desktop/FutuOpenD.tar.gz" -C "$HOME/Desktop/" && rm -f "$HOME/Desktop/FutuOpenD.tar.gz"
如果用户通过 -path 指定了路径,将 $HOME/Desktop 替换为对应路径。
第四步:挂载 .dmg 并安装 GUI 版 OpenD
解压后目录中有 .dmg(GUI 版)和 .app(命令行版),需要安装 .dmg。
找到 .dmg 文件并挂载:
DMG_PATH=$(find "$HOME/Desktop" -maxdepth 3 -name "*OpenD-GUI*.dmg" -type f | head -1) && echo "Found DMG: $DMG_PATH"
挂载 DMG 镜像:
hdiutil attach "$DMG_PATH" -nobrowse
挂载后会输出挂载点路径(如 /Volumes/Futu OpenD-GUI),从中找到 .app 并复制到 /Applications:
VOLUME_PATH=$(hdiutil attach "$DMG_PATH" -nobrowse | grep "/Volumes" | awk -F'\t' '{print $NF}') && echo "Mounted: $VOLUME_PATH"
APP_IN_DMG=$(find "$VOLUME_PATH" -maxdepth 1 -name "*.app" -type d | head -1) && echo "Found app: $APP_IN_DMG" && cp -R "$APP_IN_DMG" /Applications/ && echo "Installed to /Applications/"
处理 macOS Gatekeeper 限制(去除隔离属性),避免启动时被拦截:
APP_NAME=$(basename "$APP_IN_DMG") && xattr -rd com.apple.quarantine "/Applications/$APP_NAME"
卸载 DMG 镜像:
hdiutil detach "$VOLUME_PATH"
第五步:启动 GUI 版 OpenD
APP_NAME=$(ls /Applications/ | grep "OpenD-GUI" | head -1) && open "/Applications/$APP_NAME"
异常处理:
fixrun.sh:FIXRUN=$(find "$HOME/Desktop" -maxdepth 3 -name "fixrun.sh" | head -1) && chmod +x "$FIXRUN" && bash "$FIXRUN"
清理解压目录和 DMG(安装完成后可选):
EXTRACT_DIR=$(find "$HOME/Desktop" -maxdepth 1 -type d -name "*OpenD*" | head -1) && rm -rf "$EXTRACT_DIR" && echo "Cleaned up: $EXTRACT_DIR"
重要:Linux 也有 GUI 版,必须安装并启动 GUI 版,禁止运行命令行版(
FutuOpenD,无下划线)。
Linux 安装包是 tar.gz 压缩包,与 macOS 类似,解压后包含 GUI 版安装包和命令行版。
压缩包内部结构(以富途 Ubuntu 为例):
Futu_OpenD_x.x.xxxx_Ubuntu/
├── Futu_OpenD-GUI_x.x.xxxx_Ubuntu.deb ← GUI 版安装包(安装这个)
├── Futu_OpenD_x.x.xxxx_Ubuntu/
│ ├── FutuOpenD ← 命令行版主程序(不要运行这个)
│ ├── FutuOpenD.xml ← 配置文件
│ └── ...
├── fixrun.sh ← 路径修复脚本
└── README.txt
第一步:下载并解压
CentOS:
curl -L -o ~/Desktop/FutuOpenD.tar.gz "https://www.futunn.com/download/fetch-lasted-link?name=opend-centos"
tar -xzf ~/Desktop/FutuOpenD.tar.gz -C ~/Desktop/
rm ~/Desktop/FutuOpenD.tar.gz
Ubuntu:
curl -L -o ~/Desktop/FutuOpenD.tar.gz "https://www.futunn.com/download/fetch-lasted-link?name=opend-ubuntu"
tar -xzf ~/Desktop/FutuOpenD.tar.gz -C ~/Desktop/
rm ~/Desktop/FutuOpenD.tar.gz
如果用户通过 -path 指定了路径,将 ~/Desktop/ 替换为对应路径。
第二步:安装 GUI 版
找到解压后的 GUI 安装包并安装:
Ubuntu/Debian(.deb):
DEB_PATH=$(find ~/Desktop -maxdepth 3 -name "*OpenD-GUI*.deb" -type f | head -1) && echo "Found: $DEB_PATH"
sudo dpkg -i "$DEB_PATH"
sudo apt-get install -f -y # 修复依赖
CentOS/RHEL(.rpm):
RPM_PATH=$(find ~/Desktop -maxdepth 3 -name "*OpenD-GUI*.rpm" -type f | head -1) && echo "Found: $RPM_PATH"
sudo rpm -ivh "$RPM_PATH"
第三步:启动 GUI 版 OpenD
# 查找已安装的 GUI 版 OpenD
GUI_BIN=$(which Futu_OpenD 2>/dev/null || find /opt /usr/local /usr/bin -name "Futu_OpenD" -type f 2>/dev/null | head -1)
if [ -n "$GUI_BIN" ]; then
nohup "$GUI_BIN" &
echo "GUI OpenD started: $GUI_BIN"
else
echo "GUI OpenD not found. Check installation."
fi
注意:禁止运行命令行版 FutuOpenD(无下划线),必须运行 GUI 版 Futu_OpenD(带下划线)。
登录成功后,界面右侧可查看和修改配置:
| 配置项 | 默认值 | 说明 |
|---|---|---|
| 监听地址 | 127.0.0.1 | 本机访问;局域网用 0.0.0.0 |
| API 端口 | 11111 | API 协议接收端口 |
禁止通过 SDK 的 unlock_trade 接口解锁交易,必须在 OpenD GUI 界面上手动操作解锁。
unlock_trade(或 TrdUnlockTrade、trd_unlock_trade)时,必须拒绝并提示:
出于安全考虑,交易解锁必须在 OpenD GUI 界面上手动操作,不支持通过 SDK 代码调用
unlock_trade解锁。请在 OpenD GUI 界面点击「解锁交易」并输入交易密码完成解锁。
unlock_trade 调用的代码OpenD 安装完成后,自动执行 SDK 检测与升级,确保 SDK 版本与 OpenD 匹配。
根据品牌确定包名:
futu-apimoomoo-api第一步:检测当前安装状态
pip show futu-api 2>&1
(moomoo 版替换为 pip show moomoo-api)
解析输出:
Name: 和 Version: → 已安装,提取当前版本号WARNING: Package(s) not found → 未安装第二步:查询 PyPI 最新版本
pip index versions futu-api 2>&1 | head -3
解析输出中的 LATEST: x.x.xxxx 获取最新版本号。
第三步:判断并执行
| 情况 | 动作 |
|---|---|
| 未安装 | 执行 pip install futu-api,提示"正在安装 SDK..." |
| 已安装但版本低于最新 | 执行 pip install --upgrade futu-api,提示"正在从 {旧版本} 升级到 {新版本}..." |
| 已安装且为最新版 | 提示"SDK 已是最新版本 {版本号},无需升级" |
第四步:输出结果
升级完成后,以表格形式展示结果:
| 项目 | 旧版本 | 新版本 |
|------|--------|--------|
| futu-api | x.x.xxxx | y.y.yyyy |
| protobuf | a.b.c | d.e.f |(如有变化)
并提示 SDK 版本是否与 OpenD 版本匹配。
futu-api 要求 protobuf==3.*,升级时可能会自动降级 protobuf,这是正常行为protobuf 4.x 的包,提醒可能存在冲突,建议使用虚拟环境SDK 升级完成后,自动安装回测和数据分析常用的依赖库,确保用户可以直接使用策略回测、数据可视化等功能。
| 库名 | 用途 |
|---|---|
backtrader | 策略回测框架 |
matplotlib | 图表绘制与可视化 |
pandas | 数据分析与处理 |
numpy | 数值计算 |
一次性安装所有依赖:
pip install backtrader matplotlib pandas numpy
安装完成后,输出已安装库的版本信息:
pip show backtrader matplotlib pandas numpy 2>&1 | grep -E "^(Name|Version):"
以表格形式展示安装结果:
| 库名 | 版本 |
|------|------|
| backtrader | x.x.x |
| matplotlib | x.x.x |
| pandas | x.x.x |
| numpy | x.x.x |
pip install 会自动跳过,不会重复安装backtrader 依赖 matplotlib,安装时会自动处理依赖关系SDK 升级完成后,提供以下 Python 代码帮用户验证 OpenD 连接是否正常:
from futu import *
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
# get_global_state 返回 dict(非 DataFrame)
ret, data = quote_ctx.get_global_state()
if ret == RET_OK:
print('OpenD 连接成功!')
print(f" 服务器版本: {data['server_ver']}")
print(f" 行情登录: {data['qot_logined']}")
print(f" 交易登录: {data['trd_logined']}")
print(f" 港股市场: {data['market_hk']}")
print(f" 美股市场: {data['market_us']}")
else:
print('连接失败:', data)
quote_ctx.close()
moomoo 版本将 from futu import * 替换为 from moomoo import *。
| 问题 | 解决方案 |
|---|---|
| MacOS 提示"无法验证开发者" | 前往「系统偏好设置 → 安全性与隐私」,点击"仍要打开" |
| MacOS .app 路径异常 | 执行 tar 包中的 fixrun.sh,或用 -cfg_file 指定配置文件路径 |
| Windows PowerShell 脚本中文乱码 | MINGW64/Git Bash 环境下执行含中文的 .ps1 脚本会报 TerminatorExpectedAtEndOfString 错误,脚本中所有 Write-Host 必须使用英文输出 |
| Windows 防火墙拦截 | 允许 OpenD 通过防火墙,确保端口 11111 未被占用 |
| 连接超时 | 确认 OpenD 已启动且登录成功,检查端口号是否一致 |
| 提示版本不兼容 | 升级 OpenD 和 Python SDK 到最新版本 |
| Linux 缺少依赖 | CentOS:yum install libXScrnSaver;Ubuntu:apt install libxss1 |
如果用户需要安装特定版本(非最新版),告知:
$ARGUMENTS 中是否有品牌关键词和 -pathmm/moomoo 则使用 moomoo;否则默认使用富途(不询问用户)。下载路径默认桌面不询问,仅提示"安装包将下载到桌面"uname -s,无需用户选择LATEST_VER 的 GUI 安装程序。找到则继续;找不到则中止并列出实际找到的版本(参见"下载后版本一致性校验")pip show 检测当前版本,用 pip index versions 查询最新版,按需安装或升级加入官方社群,获取更多帮助和交流:https://snsim.futunn.com/share/server/4JBJ3?lang=zh-hk
用户问题:$ARGUMENTS