# 币安永续合约定时平仓 定时从币安获取永续合约持仓,当满足条件时对该合约的多空进行限价平仓。 **技术栈**:币安合约使用 [python-binance](https://github.com/sammchardy/python-binance) 的 **AsyncClient(aio 异步接口)**,Redis 使用 [redis.asyncio](https://redis.readthedocs.io/en/stable/examples/asyncio_examples.html)(与 aioredis 用法兼容的异步接口)。 ## 逻辑 1. **平仓前置条件**(不满足则直接退出,不执行后续平仓): - 获取当前账户**总未实现盈亏**,写入 Redis Sorted Set(历史记录); - 取**近 N 分钟**(默认 5 分钟)内历史中的**最小总未实现盈亏**; - 仅当 **当前总未实现盈亏 - 该最小 > 配置阈值**(默认 2 USDT)时,才继续执行平仓逻辑;否则退出。 2. **定时拉取持仓**:按配置间隔调用币安 `GET /fapi/v2/positionRisk` 获取 USDT 永续持仓。 3. **触发条件**(满足其一即对该合约平仓): - Redis 中指定 key 的 Set 里包含该合约 symbol(如 `BTCUSDT`)时强制平仓; - 该合约**多空名义价值总和** < `notional_small_close_threshold`(默认 30 USDT)**且**未实现盈亏 > `small_close_min_profit`(默认 0.03 USDT)。 4. **平仓方式**: - **多头**:限价卖出,价格 = 当前价 × 1.003; - **空头**:限价买入,价格 = 当前价 × 0.997。 4. 若因 Redis 触发平仓,平仓后会从该 Set 中移除该 symbol。 ## 配置(Dynaconf) 配置通过 [Dynaconf](https://www.dynaconf.com/) 加载,按优先级:环境变量 > `.secrets.toml` > `settings.toml`。环境变量需加前缀 `BINANCE_POSITION_`(如 `BINANCE_POSITION_BINANCE_API_KEY`)。 - **settings.toml**:所有非敏感配置均在此文件,可直接修改。 - **.secrets.toml**:仅放敏感信息(复制 `.secrets.toml.example` 为 `.secrets.toml` 后填写),勿提交。 | 配置项 | 说明 | 所在文件 | |--------|------|----------| | `binance_api_key` | 币安 API Key(需合约权限) | .secrets.toml | | `binance_api_secret` | 币安 API Secret | .secrets.toml | | `binance_base_url` | 合约 API 地址 | settings.toml | | `redis_url` | Redis 连接 | settings.toml | | `redis_close_key` | 强制平仓合约的 Redis Set key | settings.toml | | `redis_unrealized_profit_history_key` | 总未实现盈亏历史的 Sorted Set key,用于平仓前置条件,默认 `close_position:unrealized_profit_history` | settings.toml | | `unrealized_profit_window_seconds` | 平仓前置条件:近 N 秒内最小总未实现盈亏作为基准,默认 300(5 分钟) | settings.toml | | `unrealized_profit_min_rise` | 平仓前置条件:当前总未实现盈亏 - 近 N 秒最小 须大于此值(USDT)才执行平仓,默认 2 | settings.toml | | `notional_threshold` | 大仓位阈值(USDT):多空价值总和大于此值且盈利大于 notional_large_close_min_profit 时平仓,默认 50 | settings.toml | | `notional_large_close_min_profit` | 大仓位平仓最低盈利(USDT):大仓位未实现盈亏须大于此值,默认 0.3 | settings.toml | | `notional_small_close_threshold` | 小仓位平仓阈值(USDT):多空价值总和小于此值且盈利大于 small_close_min_profit 时平仓,默认 30 | settings.toml | | `small_close_min_profit` | 小仓位平仓最低盈利(USDT):小仓位未实现盈亏须大于此值,默认 0.03 | settings.toml | | `interval_seconds` | 轮询间隔(秒),当前流程备用 | settings.toml | | `dry_run` | 默认 `true`(dry-run,不真实下单);设为 `false` 或 `DRY_RUN=0` 时真实下单 | settings.toml | **默认 dry-run**:脚本默认只跑全流程并打印将下的单,不真实下单、不从 Redis 移除。要真实平仓时,在 `settings.toml` 中设置 `dry_run = false`,或运行前设置环境变量 `DRY_RUN=0`。 ## 安装与运行 使用项目内 venv 初始化环境并运行: ```bash # 创建虚拟环境(若尚未创建) python3 -m venv .venv # 激活虚拟环境并安装依赖 .venv/bin/pip install -r requirements.txt # 运行 .venv/bin/python position_closer.py ``` 或先激活 venv 再执行: ```bash source .venv/bin/activate # Linux/macOS pip install -r requirements.txt python position_closer.py ``` ## 每小时定时运行 项目内提供 `run_position_closer.sh`: ```bash # 运行一次 ./run_position_closer.sh # 前台每 1 小时运行一次(循环,Ctrl+C 停止) ./run_position_closer.sh loop ``` **用 crontab 每小时整点执行一次**(将路径换成你的项目目录): ```bash crontab -e # 添加一行(整点执行): 0 * * * * /home/yanhaoyang/Projects/bn-pc/run_position_closer.sh ``` ## 通过 Redis 指定平仓合约 向 Redis Set 添加需要平仓的合约 symbol 即可,下一轮轮询会对其多空进行平仓,并在平仓后从 Set 中移除: ```bash redis-cli SADD close_position:contracts BTCUSDT ETHUSDT ``` (若修改了 `redis_close_key`,请使用你配置的 key。) ## 注意事项 - 支持**单向持仓**(positionSide=BOTH)与**双向持仓**(LONG/SHORT)。 - 平仓使用**限价单**,若市价偏离较多可能不会立刻成交,需自行在交易所查看或撤单改市价。 - API Key 需有 USDT 永续合约的读取与交易权限;建议先用测试网验证。