docs(env): unify auto-transfer config across four exchanges
Align .env.example blocks and add sync script to merge AUTO_TRANSFER_* into existing instance .env files without touching API secrets. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -130,12 +130,17 @@ MONITOR_POLL_SECONDS=3
|
|||||||
# 使用可用资金时的缓冲比例(如0.98代表用98%)
|
# 使用可用资金时的缓冲比例(如0.98代表用98%)
|
||||||
FULL_MARGIN_BUFFER_RATIO=0.98
|
FULL_MARGIN_BUFFER_RATIO=0.98
|
||||||
|
|
||||||
# 自动划转:将目标账户补足到 AUTO_TRANSFER_AMOUNT(ccxt:funding↔swap 等)
|
# =============================================================================
|
||||||
|
# 自动划转(页顶「将 swap 补足到 XU」;与 DAILY_START_CAPITAL 独立,需一致时请设为相同值)
|
||||||
|
# =============================================================================
|
||||||
AUTO_TRANSFER_ENABLED=false
|
AUTO_TRANSFER_ENABLED=false
|
||||||
|
# 合约/交易账户(AUTO_TRANSFER_TO)补足到的 USDT 总额,非每日开仓基数
|
||||||
AUTO_TRANSFER_AMOUNT=30
|
AUTO_TRANSFER_AMOUNT=30
|
||||||
AUTO_TRANSFER_FROM=funding
|
AUTO_TRANSFER_FROM=funding
|
||||||
AUTO_TRANSFER_TO=swap
|
AUTO_TRANSFER_TO=swap
|
||||||
TRANSFER_CCY=USDT
|
TRANSFER_CCY=USDT
|
||||||
|
# 北京时间该整点小时内尝试;账簿按 UTC 自然日去重
|
||||||
|
AUTO_TRANSFER_BJ_HOUR=8
|
||||||
# 强制清仓整点(北京时间,默认 0=凌晨00点)
|
# 强制清仓整点(北京时间,默认 0=凌晨00点)
|
||||||
FORCE_CLOSE_BJ_HOUR=0
|
FORCE_CLOSE_BJ_HOUR=0
|
||||||
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
|
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
|
||||||
@@ -182,5 +187,4 @@ AI_MODEL=huihui_ai/deepseek-r1-abliterated:latest
|
|||||||
# DEFAULT_TRADE_STYLE=trend
|
# DEFAULT_TRADE_STYLE=trend
|
||||||
|
|
||||||
APP_TIMEZONE=Asia/Shanghai
|
APP_TIMEZONE=Asia/Shanghai
|
||||||
AUTO_TRANSFER_BJ_HOUR=8
|
|
||||||
# TRADING_DAY_RESET_HOUR 现在表示「北京时间」整点,默认 8 点起算新交易日;开仓整点限制见 TRADING_DAY_RESET_OPEN_GUARD_ENABLED
|
# TRADING_DAY_RESET_HOUR 现在表示「北京时间」整点,默认 8 点起算新交易日;开仓整点限制见 TRADING_DAY_RESET_OPEN_GUARD_ENABLED
|
||||||
|
|||||||
@@ -136,12 +136,17 @@ RECONCILE_FLAT_CONFIRM_POLLS=3
|
|||||||
# 使用可用资金时的缓冲比例(如0.98代表用98%)
|
# 使用可用资金时的缓冲比例(如0.98代表用98%)
|
||||||
FULL_MARGIN_BUFFER_RATIO=0.98
|
FULL_MARGIN_BUFFER_RATIO=0.98
|
||||||
|
|
||||||
# 自动划转:将目标账户补足到 AUTO_TRANSFER_AMOUNT
|
# =============================================================================
|
||||||
|
# 自动划转(页顶「将 swap 补足到 XU」;与 DAILY_START_CAPITAL 独立,需一致时请设为相同值)
|
||||||
|
# =============================================================================
|
||||||
AUTO_TRANSFER_ENABLED=false
|
AUTO_TRANSFER_ENABLED=false
|
||||||
|
# 交易账户(AUTO_TRANSFER_TO)补足到的 USDT 总额,非每日开仓基数
|
||||||
AUTO_TRANSFER_AMOUNT=30
|
AUTO_TRANSFER_AMOUNT=30
|
||||||
AUTO_TRANSFER_FROM=funding
|
AUTO_TRANSFER_FROM=funding
|
||||||
AUTO_TRANSFER_TO=swap
|
AUTO_TRANSFER_TO=swap
|
||||||
TRANSFER_CCY=USDT
|
TRANSFER_CCY=USDT
|
||||||
|
# 北京时间该整点小时内尝试;账簿按 UTC 自然日去重
|
||||||
|
AUTO_TRANSFER_BJ_HOUR=8
|
||||||
# 强制清仓整点(北京时间,默认 0=凌晨00点)
|
# 强制清仓整点(北京时间,默认 0=凌晨00点)
|
||||||
FORCE_CLOSE_BJ_HOUR=0
|
FORCE_CLOSE_BJ_HOUR=0
|
||||||
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
|
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
|
||||||
@@ -186,5 +191,4 @@ AI_MODEL=huihui_ai/deepseek-r1-abliterated:latest
|
|||||||
# DEFAULT_TRADE_STYLE=trend
|
# DEFAULT_TRADE_STYLE=trend
|
||||||
|
|
||||||
APP_TIMEZONE=Asia/Shanghai
|
APP_TIMEZONE=Asia/Shanghai
|
||||||
AUTO_TRANSFER_BJ_HOUR=8
|
|
||||||
# TRADING_DAY_RESET_HOUR 现在表示「北京时间」整点,默认 8 点起算新交易日;开仓整点限制见 TRADING_DAY_RESET_OPEN_GUARD_ENABLED
|
# TRADING_DAY_RESET_HOUR 现在表示「北京时间」整点,默认 8 点起算新交易日;开仓整点限制见 TRADING_DAY_RESET_OPEN_GUARD_ENABLED
|
||||||
|
|||||||
@@ -104,12 +104,17 @@ MONITOR_POLL_SECONDS=3
|
|||||||
# 使用可用资金时的缓冲比例(如0.98代表用98%)
|
# 使用可用资金时的缓冲比例(如0.98代表用98%)
|
||||||
FULL_MARGIN_BUFFER_RATIO=0.98
|
FULL_MARGIN_BUFFER_RATIO=0.98
|
||||||
|
|
||||||
# 自动划转:将目标账户补足到 AUTO_TRANSFER_AMOUNT
|
# =============================================================================
|
||||||
|
# 自动划转(页顶「将 swap 补足到 XU」;与 DAILY_START_CAPITAL 独立,需一致时请设为相同值)
|
||||||
|
# =============================================================================
|
||||||
AUTO_TRANSFER_ENABLED=false
|
AUTO_TRANSFER_ENABLED=false
|
||||||
|
# 交易账户(AUTO_TRANSFER_TO)补足到的 USDT 总额,非每日开仓基数
|
||||||
AUTO_TRANSFER_AMOUNT=30
|
AUTO_TRANSFER_AMOUNT=30
|
||||||
AUTO_TRANSFER_FROM=funding
|
AUTO_TRANSFER_FROM=funding
|
||||||
AUTO_TRANSFER_TO=swap
|
AUTO_TRANSFER_TO=swap
|
||||||
TRANSFER_CCY=USDT
|
TRANSFER_CCY=USDT
|
||||||
|
# 北京时间该整点小时内尝试;账簿按 UTC 自然日去重
|
||||||
|
AUTO_TRANSFER_BJ_HOUR=8
|
||||||
# 强制清仓整点(北京时间,默认 0=凌晨00点)
|
# 强制清仓整点(北京时间,默认 0=凌晨00点)
|
||||||
FORCE_CLOSE_BJ_HOUR=0
|
FORCE_CLOSE_BJ_HOUR=0
|
||||||
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
|
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
|
||||||
@@ -160,5 +165,4 @@ AI_MODEL=huihui_ai/deepseek-r1-abliterated:latest
|
|||||||
# TREND_PREVIEW_MAX_BALANCE_DRIFT_PCT=5
|
# TREND_PREVIEW_MAX_BALANCE_DRIFT_PCT=5
|
||||||
|
|
||||||
APP_TIMEZONE=Asia/Shanghai
|
APP_TIMEZONE=Asia/Shanghai
|
||||||
AUTO_TRANSFER_BJ_HOUR=8
|
|
||||||
# TRADING_DAY_RESET_HOUR 现在表示「北京时间」整点,默认 8 点起算新交易日;开仓整点限制见 TRADING_DAY_RESET_OPEN_GUARD_ENABLED
|
# TRADING_DAY_RESET_HOUR 现在表示「北京时间」整点,默认 8 点起算新交易日;开仓整点限制见 TRADING_DAY_RESET_OPEN_GUARD_ENABLED
|
||||||
|
|||||||
@@ -95,12 +95,17 @@ BREAKEVEN_EXCHANGE_MIN_INTERVAL_SEC=60
|
|||||||
# 使用可用资金时的缓冲比例(如0.98代表用98%)
|
# 使用可用资金时的缓冲比例(如0.98代表用98%)
|
||||||
FULL_MARGIN_BUFFER_RATIO=0.98
|
FULL_MARGIN_BUFFER_RATIO=0.98
|
||||||
|
|
||||||
# 自动划转:将目标账户补足到 AUTO_TRANSFER_AMOUNT
|
# =============================================================================
|
||||||
|
# 自动划转(页顶「将 swap 补足到 XU」;与 DAILY_START_CAPITAL 独立,需一致时请设为相同值)
|
||||||
|
# =============================================================================
|
||||||
AUTO_TRANSFER_ENABLED=false
|
AUTO_TRANSFER_ENABLED=false
|
||||||
|
# 交易账户(AUTO_TRANSFER_TO)补足到的 USDT 总额,非每日开仓基数
|
||||||
AUTO_TRANSFER_AMOUNT=30
|
AUTO_TRANSFER_AMOUNT=30
|
||||||
AUTO_TRANSFER_FROM=funding
|
AUTO_TRANSFER_FROM=funding
|
||||||
AUTO_TRANSFER_TO=swap
|
AUTO_TRANSFER_TO=swap
|
||||||
TRANSFER_CCY=USDT
|
TRANSFER_CCY=USDT
|
||||||
|
# 北京时间该整点小时内尝试;账簿按 UTC 自然日去重
|
||||||
|
AUTO_TRANSFER_BJ_HOUR=8
|
||||||
# 强制清仓整点(北京时间,默认 0=凌晨00点)
|
# 强制清仓整点(北京时间,默认 0=凌晨00点)
|
||||||
FORCE_CLOSE_BJ_HOUR=0
|
FORCE_CLOSE_BJ_HOUR=0
|
||||||
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
|
# 是否启用强制清仓(默认关闭,true 才会在整点执行)
|
||||||
@@ -148,7 +153,6 @@ AI_MODEL=huihui_ai/deepseek-r1-abliterated:latest
|
|||||||
# DEFAULT_TRADE_STYLE=trend
|
# DEFAULT_TRADE_STYLE=trend
|
||||||
|
|
||||||
APP_TIMEZONE=Asia/Shanghai
|
APP_TIMEZONE=Asia/Shanghai
|
||||||
AUTO_TRANSFER_BJ_HOUR=8
|
|
||||||
# TRADING_DAY_RESET_HOUR 现在表示「北京时间」整点,默认 8 点起算新交易日/可开仓等
|
# TRADING_DAY_RESET_HOUR 现在表示「北京时间」整点,默认 8 点起算新交易日/可开仓等
|
||||||
|
|
||||||
# 默认启用「北京时间 TRADING_DAY_RESET_HOUR 前禁止新开仓」;网页顶栏可运行时切换(写入 DB)
|
# 默认启用「北京时间 TRADING_DAY_RESET_HOUR 前禁止新开仓」;网页顶栏可运行时切换(写入 DB)
|
||||||
|
|||||||
@@ -85,6 +85,16 @@ bash deploy/setup_env.sh
|
|||||||
3. 服务器长期运行见各目录 **《部署文档.md》**(SSH SOCKS、PM2)。
|
3. 服务器长期运行见各目录 **《部署文档.md》**(SSH SOCKS、PM2)。
|
||||||
4. **多账户中控**(`manual_trading_hub`):编辑 `manual_trading_hub/.env`(`HUB_PASSWORD`、`HUB_BRIDGE_TOKEN` 等与四实例一致),再 `pm2 start ecosystem.config.cjs`;验收 `bash manual_trading_hub/scripts/verify_hub_deploy.sh`。详见 [manual_trading_hub/部署文档.md](../manual_trading_hub/部署文档.md)、[常见问题.md](../manual_trading_hub/常见问题.md)。
|
4. **多账户中控**(`manual_trading_hub`):编辑 `manual_trading_hub/.env`(`HUB_PASSWORD`、`HUB_BRIDGE_TOKEN` 等与四实例一致),再 `pm2 start ecosystem.config.cjs`;验收 `bash manual_trading_hub/scripts/verify_hub_deploy.sh`。详见 [manual_trading_hub/部署文档.md](../manual_trading_hub/部署文档.md)、[常见问题.md](../manual_trading_hub/常见问题.md)。
|
||||||
|
|
||||||
|
## 四所 `.env` 自动划转项(已有 .env 时)
|
||||||
|
|
||||||
|
`AUTO_TRANSFER_AMOUNT` 等与 `DAILY_START_CAPITAL` **独立**;四所 `.env.example` 已统一注释。若服务器上已有 `.env`,可合并写入(不覆盖 API 密钥):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/sync_four_exchange_transfer_env.py
|
||||||
|
# 缺 AUTO_TRANSFER_AMOUNT 时会沿用该文件中的 DAILY_START_CAPITAL
|
||||||
|
pm2 restart crypto-monitor-binance crypto-monitor-okx crypto-monitor-gate crypto-monitor-gate-bot
|
||||||
|
```
|
||||||
|
|
||||||
## 依赖说明
|
## 依赖说明
|
||||||
|
|
||||||
- 四个监控子项目共用仓库根目录 **[requirements.txt](../requirements.txt)**。
|
- 四个监控子项目共用仓库根目录 **[requirements.txt](../requirements.txt)**。
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
将自动划转 / 币安资金账户相关项写入四所实例 .env(已存在则更新,缺失则追加)。
|
||||||
|
|
||||||
|
用法(仓库根目录):
|
||||||
|
python scripts/sync_four_exchange_transfer_env.py
|
||||||
|
python scripts/sync_four_exchange_transfer_env.py --dry-run
|
||||||
|
|
||||||
|
不修改 API 密钥与其它自定义项;若 .env 不存在则跳过(请先从 .env.example 复制)。
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
INSTANCES = (
|
||||||
|
"crypto_monitor_binance",
|
||||||
|
"crypto_monitor_okx",
|
||||||
|
"crypto_monitor_gate",
|
||||||
|
"crypto_monitor_gate_bot",
|
||||||
|
)
|
||||||
|
|
||||||
|
# 四所统一(页顶「将 swap 补足到 XU」= AUTO_TRANSFER_AMOUNT,与 DAILY_START_CAPITAL 独立)
|
||||||
|
COMMON_KEYS = {
|
||||||
|
"AUTO_TRANSFER_ENABLED": "false",
|
||||||
|
"AUTO_TRANSFER_FROM": "funding",
|
||||||
|
"AUTO_TRANSFER_TO": "swap",
|
||||||
|
"TRANSFER_CCY": "USDT",
|
||||||
|
"AUTO_TRANSFER_BJ_HOUR": "8",
|
||||||
|
}
|
||||||
|
|
||||||
|
BINANCE_ONLY = {
|
||||||
|
"BINANCE_FUNDING_INCLUDE_SPOT": "false",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_env(path: str) -> list[str]:
|
||||||
|
if not os.path.isfile(path):
|
||||||
|
return []
|
||||||
|
with open(path, "r", encoding="utf-8", errors="ignore") as f:
|
||||||
|
return f.read().replace("\r\n", "\n").replace("\r", "\n").splitlines()
|
||||||
|
|
||||||
|
|
||||||
|
def _env_get(lines: list[str], key: str) -> str | None:
|
||||||
|
pat = re.compile(r"^\s*" + re.escape(key) + r"\s*=\s*(.*)\s*$")
|
||||||
|
for line in lines:
|
||||||
|
m = pat.match(line)
|
||||||
|
if m:
|
||||||
|
return m.group(1).strip().strip('"').strip("'")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _upsert(lines: list[str], key: str, value: str) -> list[str]:
|
||||||
|
pat = re.compile(r"^\s*" + re.escape(key) + r"\s*=")
|
||||||
|
out = []
|
||||||
|
replaced = False
|
||||||
|
for line in lines:
|
||||||
|
if pat.match(line):
|
||||||
|
if not replaced:
|
||||||
|
out.append(f"{key}={value}")
|
||||||
|
replaced = True
|
||||||
|
continue
|
||||||
|
out.append(line)
|
||||||
|
if not replaced:
|
||||||
|
if out and out[-1].strip():
|
||||||
|
out.append("")
|
||||||
|
out.append(f"{key}={value}")
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_transfer_block(lines: list[str], extra: dict[str, str]) -> list[str]:
|
||||||
|
daily = _env_get(lines, "DAILY_START_CAPITAL")
|
||||||
|
amount = _env_get(lines, "AUTO_TRANSFER_AMOUNT")
|
||||||
|
if amount is None:
|
||||||
|
amount = daily if daily else "30"
|
||||||
|
keys = dict(COMMON_KEYS)
|
||||||
|
keys["AUTO_TRANSFER_AMOUNT"] = amount
|
||||||
|
keys.update(extra)
|
||||||
|
for k, v in keys.items():
|
||||||
|
lines = _upsert(lines, k, v)
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def sync_one(dir_name: str, dry_run: bool) -> str:
|
||||||
|
env_path = os.path.join(REPO, dir_name, ".env")
|
||||||
|
if not os.path.isfile(env_path):
|
||||||
|
return f"SKIP {dir_name}: 无 .env(请 cp .env.example .env)"
|
||||||
|
lines = _parse_env(env_path)
|
||||||
|
extra = dict(BINANCE_ONLY) if dir_name == "crypto_monitor_binance" else {}
|
||||||
|
new_lines = _ensure_transfer_block(lines, extra)
|
||||||
|
if new_lines == lines:
|
||||||
|
return f"OK {dir_name}: 已是最新"
|
||||||
|
if dry_run:
|
||||||
|
return f"DRY {dir_name}: 将更新 {len([1 for a,b in zip(lines,new_lines) if a!=b])}+ 行"
|
||||||
|
with open(env_path, "w", encoding="utf-8", newline="\n") as f:
|
||||||
|
f.write("\n".join(new_lines))
|
||||||
|
if new_lines and new_lines[-1].strip():
|
||||||
|
f.write("\n")
|
||||||
|
amt = _env_get(new_lines, "AUTO_TRANSFER_AMOUNT")
|
||||||
|
return f"DONE {dir_name}: AUTO_TRANSFER_AMOUNT={amt}"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--dry-run", action="store_true")
|
||||||
|
args = ap.parse_args()
|
||||||
|
for name in INSTANCES:
|
||||||
|
print(sync_one(name, args.dry_run))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user