This commit is contained in:
薇薇安 2026-03-03 09:21:38 +08:00
parent 4ea1c53813
commit 6858ddad6b
2 changed files with 130 additions and 3 deletions

View File

@ -0,0 +1,98 @@
# 减少亏损的配置操作步骤
基于「最近一天亏损分析」的结论,按下面步骤改配置即可生效(无需改代码,改完保存后配置会热更新,交易进程下一轮扫描即用新值)。
---
## 一、在哪里改
- **前端**:登录系统 → 左侧 **「配置」** 或 **「全局配置」**(管理员用全局配置可改所有账号默认值)。
- **按账号**:配置页顶部选好要改的**账号**,再改下面项,保存后只对该账号生效。
---
## 二、建议先改的几项(优先顺序)
### 1. 确保 4H 上涨时禁止开空(减少空单在反弹里被扫)
| 配置项 | 建议值 | 说明 |
|--------|--------|------|
| **BLOCK_SHORT_WHEN_4H_UP** | **true** | 4H 趋势为上涨时禁止开空,避免像 WLD/XLM/PENGU/SIREN 那样做空后被反弹打止损。 |
若当前是 `false`,改成 `true` 并保存。
---
### 2. 市场方案(牛/熊/正常)
| 配置项 | 建议值 | 说明 |
|--------|--------|------|
| **MARKET_SCHEME** | **normal****bull** | 若你认为近期偏多,可设为 **bull**:牛市时系统会禁止开空,进一步减少逆势空单。 |
- 想自动识别牛熊:把 **AUTO_MARKET_SCHEME_ENABLED** 设为 **true**,并保证服务器上定时跑 `scripts/update_market_scheme.py --apply`(见该脚本说明)。
- 不自动的话就手动把 **MARKET_SCHEME** 设为 **bull** / **bear** / **normal**
---
### 3. 放宽止损,减少「约 3% 被洗」再反向
亏损单多在约 2.8%3.2% 出场,可把止损略放宽,给波动留空间(仍会止损,只是不那么紧)。
| 配置项 | 原常见值 | 建议值 | 说明 |
|--------|----------|--------|------|
| **STOP_LOSS_PERCENT** | 0.050.085%8% | **0.080.10**8%10% | 保证金比例止损。8%10% 仍能控单笔风险,但比 5% 不易被正常波动扫掉。 |
| **ATR_STOP_LOSS_MULTIPLIER** | 2.0 | **2.53.0** | 用 ATR 动态止损时,倍数大一点 = 止损距离稍远,适合波动大的山寨。 |
**USE_ATR_STOP_LOSS** 为 true优先调 **ATR_STOP_LOSS_MULTIPLIER**;否则主要调 **STOP_LOSS_PERCENT**
---
### 4. 提高信号门槛(少做弱信号单)
| 配置项 | 建议值 | 说明 |
|--------|--------|------|
| **MIN_SIGNAL_STRENGTH** | **68** | 最小信号强度(0-10)。提高到 68 会少很多单,但单笔质量更好,适合当前胜率偏低时。 |
---
### 5. 周日 / 晚间(可选)
若亏损多发生在周日或晚间 2223 点、910 点,可加强限制:
| 配置项 | 建议值 | 说明 |
|--------|--------|------|
| **SUNDAY_MAX_OPENS** | **23** | 周日最多开仓次数0=不限制。23 可压周日亏损。 |
| **SUNDAY_MIN_SIGNAL_STRENGTH** | **89** | 周日只有信号强度 ≥ 此值才开仓0=不提高。 |
| **NIGHT_HOURS_NO_OPEN_ENABLED** | **true** | 晚间禁止开新仓(配合下面起止小时)。 |
| **NIGHT_HOURS_START** / **NIGHT_HOURS_END** | 如 **21** / **6** | 北京 21:0006:00 不开新仓;**NIGHT_HOURS_ONLY_SUNDAY** = true 则仅周六晚~周日早。 |
---
## 三、操作清单(复制自查)
- [ ] **BLOCK_SHORT_WHEN_4H_UP** = true
- [ ] **MARKET_SCHEME** = normal 或 bull若偏多选 bull
- [ ] **STOP_LOSS_PERCENT** = 0.080.10,或 **ATR_STOP_LOSS_MULTIPLIER** = 2.53.0
- [ ] **MIN_SIGNAL_STRENGTH** = 68
- [ ] (可选)**SUNDAY_MAX_OPENS** = 23**SUNDAY_MIN_SIGNAL_STRENGTH** = 8
- [ ] (可选)**NIGHT_HOURS_NO_OPEN_ENABLED** = true
改完后在配置页点**保存**;配置会写入数据库/Redis交易进程下一次读配置即生效一般**无需重启**(若你部署方式有缓存,可按需重启一次交易服务)。
---
## 四、想更保守时
- **MAX_OPEN_POSITIONS** 调小(如 15 → 10减少同时持仓。
- **MAX_DAILY_ENTRIES** 调小(如 15 → 810降低频率。
- **AUTO_TRADE_ALLOW_4H_NEUTRAL** = **false**4H 震荡时不再自动开仓,只做趋势更明确的单。
---
## 五、改完如何验证
- 看**交易记录**:新开仓是否变少、空单是否明显减少。
- 看**日志**是否有「4H 趋势上涨,禁止开空」「持仓数量已达上限」「今日开仓次数已达上限」等,说明限制在生效。
- 跑一段时间后再导出一份**币安成交**,对比同样天数的盈亏与胜率。
以上均为配置层面的操作,无需改代码;若你希望「只对做空单独提高信号门槛」等更细的规则,可以再在策略里加逻辑(需改代码)。

View File

@ -1144,6 +1144,34 @@ class PositionManager:
None
)
# 缓存未命中时 REST 复核_get_open_positions 可能来自缓存,若缓存无该 symbol 会误判为无持仓,但币安实际有仓(如对冲模式、多账号缓存隔离不全、未刷新)
if not position:
live_amt = await self._get_live_position_amt(symbol, position_side=None)
if live_amt is not None and abs(live_amt) > 0:
try:
raw = await self.client.client.futures_position_information(symbol=symbol, recvWindow=20000)
for p in (raw or []):
if not isinstance(p, dict):
continue
try:
amt = float(p.get("positionAmt", 0))
except (TypeError, ValueError):
continue
if abs(amt) <= 0:
continue
position = {
'symbol': symbol,
'positionAmt': amt,
'entryPrice': float(p.get('entryPrice', 0)),
'positionSide': (p.get('positionSide') or '').strip().upper() or ('LONG' if amt > 0 else 'SHORT'),
}
logger.info(
f"{symbol} [平仓] 缓存未命中该 symbol已用 REST 拉取到持仓: amt={amt}, positionSide={position['positionSide']}"
)
break
except Exception as e:
logger.debug(f"{symbol} [平仓] REST 拉取持仓失败: {e}")
if not position:
logger.warning(f"{symbol} [平仓] 币安账户中没有持仓,可能已被平仓")
# 即使币安没有持仓,也要更新数据库状态
@ -1213,11 +1241,12 @@ class PositionManager:
# 如果更新了数据库,返回成功;否则返回失败
return updated
# 确定平仓方向(与开仓相反)
# 确定平仓方向(与开仓相反);对冲模式下使用 REST 返回的 positionSideLONG/SHORTBOTH 或缺失时按 positionAmt 推导
position_amt = position['positionAmt']
side = 'SELL' if position_amt > 0 else 'BUY'
quantity = abs(position_amt)
position_side = 'LONG' if position_amt > 0 else 'SHORT'
ps_raw = (position.get('positionSide') or '').strip().upper()
position_side = ps_raw if ps_raw in ('LONG', 'SHORT') else ('LONG' if position_amt > 0 else 'SHORT')
# 二次校验:用币安实时持仓数量兜底,避免 reduceOnly 被拒绝(-2022
live_amt = await self._get_live_position_amt(symbol, position_side=position_side)