- position_closer: 去掉 Redis 依赖,平仓条件仅名义+未实现盈亏 - requirements: 移除 redis - settings.toml: 仅保留实际使用的配置项 - 新增 Dockerfile(仅安装依赖)、docker-compose(挂载代码与配置) - 新增 .dockerignore、.gitignore(含 nohup.log) Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
5.3 KiB
Markdown
106 lines
5.3 KiB
Markdown
# 币安永续合约定时平仓
|
||
|
||
定时从币安获取永续合约持仓,当满足条件时对该合约的多空进行限价平仓。
|
||
|
||
**技术栈**:币安合约使用 [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 永续合约的读取与交易权限;建议先用测试网验证。
|