feat(config, market_scanner, position_manager, strategy): 引入市场节奏自动识别与流动性检查功能
在 `config.py` 中新增市场节奏自动识别配置,支持低波动期参数切换。更新 `market_scanner.py` 以根据市场波动情况动态调整策略,并在扫描时计算中位数以判断市场状态。同时,在 `position_manager.py` 中实现时间止损逻辑,确保在低波动期内有效管理持仓。新增流动性检查功能于 `strategy.py`,在开仓前评估市场深度与价差,提升交易决策的准确性与风险控制能力。
This commit is contained in:
parent
42480ef886
commit
48c3f946cc
100
docs/持仓与成交量低迷期优化分析.md
Normal file
100
docs/持仓与成交量低迷期优化分析.md
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
# 持仓与成交量低迷期优化分析
|
||||
|
||||
基于 `持仓记录_2026-02-17T02-22-51.json` 与「昨天到今天稳定小亏损、成交量较低」的反馈,做原因归纳和优化方案;并对照你已有的币安接口文档,标出能直接帮助的接口。
|
||||
|
||||
---
|
||||
|
||||
## 一、当前持仓快照摘要(2026-02-17)
|
||||
|
||||
| 项目 | 数值 |
|
||||
|------|------|
|
||||
| 持仓数 | 9 |
|
||||
| 多单 / 空单 | 2 / 7(偏空) |
|
||||
| 总浮盈(USDT) | 约 +0.75(该快照) |
|
||||
| 浮盈笔数 / 浮亏笔数 | 5 / 4 |
|
||||
| 浮亏标的 | FILUSDT, XLMUSDT, HUSDT, WLDUSDT |
|
||||
|
||||
说明:若「昨天到今天」整体是稳定小亏损,多半是**已平仓单**的净亏损或**持仓从浮盈回吐**;成交量低会放大滑点、费率占比和假突破,容易加剧小亏。
|
||||
|
||||
---
|
||||
|
||||
## 二、成交量偏低时「稳定小亏」的常见原因
|
||||
|
||||
1. **滑点与冲击成本**
|
||||
成交量小 → 盘口薄,市价/条件单成交价差大,开平仓都被「多砍一点」,积少成多。
|
||||
|
||||
2. **资金费率占比变高**
|
||||
持仓过夜/过结算,费率不变但单笔盈利变小,净收益容易被费率吃掉甚至变负。
|
||||
|
||||
3. **假突破增多**
|
||||
波动主要来自少量大单,技术信号(突破、金叉等)更容易假突破,开仓胜率下降。
|
||||
|
||||
4. **止盈难触发、止损先到**
|
||||
波动不足时价格磨蹭,止盈距离难达到,反而先触发止损或长时间横盘后小亏出场。
|
||||
|
||||
5. **多空结构不利**
|
||||
若做多时多头拥挤(费率负、多空比极端),或做空时空头拥挤,结构不利会放大「小亏」。
|
||||
|
||||
---
|
||||
|
||||
## 三、你已有的币安文档与可落地的优化
|
||||
|
||||
下面按「文档 → 能帮上什么」对照,方便你按文档实现或扩展。
|
||||
|
||||
| 文档 | 能帮助的优化 |
|
||||
|------|----------------|
|
||||
| **行情接口REST.txt** | exchangeInfo(规则/合约信息)、ticker/深度/K 线:用于**成交量/深度过滤**(如 24h 量、盘口深度)、**流动性检查**;低量标的可直接从扫描候选剔除或降权。 |
|
||||
| **行情ws接口.txt / ws行情推送.txt** | 实时 ticker、深度、K 线:可做**入场前二次确认**(如信号满足时再查一次深度或最近成交),减少在极薄盘口下单。 |
|
||||
| **订单交易更新推送.txt** | ORDER_TRADE_UPDATE(NEW/FILLED/TRADE):已有 User Data 时可用于**成交回报、部分成交处理**;结合「条件单触发」可更快更新 DB、减少重复操作。 |
|
||||
| **条件订单交易更新推送.txt** | 条件单/ALGO 状态:**止损/止盈/跟踪止损**触发后的实时反馈,便于统计「因何平仓」、优化 SL/TP 参数。 |
|
||||
| **ws交易接口.txt** | WS 下单(order.place / algoOrder.place):已实现「WS 条件单 + REST 回退」,**减少下单超时**,在弱网或低流动性时更稳。 |
|
||||
| **用户余额.txt** | 账户余额/可用保证金:用于**按可用保证金动态控仓**,避免在低量、高波动时过度开仓。 |
|
||||
| **账户信息流连接.txt** | 账户/持仓推送:与现有 User Data 一致,**实时保证金与强平风险**,可做风控与告警。 |
|
||||
|
||||
---
|
||||
|
||||
## 四、可落地的优化方案(按优先级)
|
||||
|
||||
### 1. 成交量/流动性过滤(直接缓解「低量小亏」)
|
||||
|
||||
- **扫描阶段**:在现有 `MIN_VOLUME_24H_STRICT` 上,可再设「**最低 24h 成交额**」或「**相对前几日量比**」门槛,低量币不进 TOP_N。
|
||||
- **开仓前**:用 **行情接口REST** 的深度(如 `GET /fapi/v1/depth`)或 24h ticker,对当前 symbol 做一次**流动性检查**(例如买一卖一价差、前几档挂单量),价差过大或挂单过薄则跳过或减小仓位。
|
||||
- **文档**:`行情接口REST.txt` 中的 ticker、depth、K 线即可支持上述逻辑。
|
||||
|
||||
### 2. 资金费率与多空结构(减少「结构不利」导致的磨损)
|
||||
|
||||
- **开仓前**:已实现的「资金费率过滤」继续保留;可适当**收紧阈值**(如做多时 `lastFundingRate > 0.0005` 就跳过),在低波动期减少费率侵蚀。
|
||||
- **扫描阶段**:已实现的「扫描阶段资金费率过滤」可保持或略加强(如 `SCAN_FUNDING_RATE_MAX_ABS` 从 0.001 降到 0.0008),避免把「费率极端」的币选进候选。
|
||||
- 若有**大户多空比 / taker 买卖比**接口(在行情或衍生文档中),可作为**排序或过滤**:与开仓方向一致则优先,极端反向则跳过或降权。
|
||||
|
||||
### 3. 出场优化(止盈难触发、亏损单拿太久)
|
||||
|
||||
- **跟踪止损**:文档与策略建议里已多次提到;在浮盈达到 X% 后改为 `TRAILING_STOP_MARKET`,**锁定部分利润**,避免回吐成小亏。
|
||||
- **时间/无盈利止损**:持仓超过 N 小时且浮盈 < 某阈值(或浮亏)→ 市价平仓或收紧止损,减少在低波动里「耗着」造成的资金占用和小亏。
|
||||
- **条件单推送**:结合「条件订单交易更新推送」统计**止损/止盈/跟踪止损**的触发比例,用于调 SL/TP 距离和跟踪止损参数。
|
||||
|
||||
### 4. 开仓节奏与仓位(低量期少开、小开)
|
||||
|
||||
- **降低开仓频率**:低量日可适当增大 `SCAN_INTERVAL` 或提高 `MIN_SIGNAL_STRENGTH`,减少「为做而做」的次优单。
|
||||
- **单笔仓位**:在配置里略降 `MAX_POSITION_PERCENT` 或固定风险比例,**单笔亏损上限变小**,整体回撤更可控。
|
||||
- **余额与风控**:用「用户余额」或账户信息流,**按可用保证金**动态限制总敞口,避免在波动放大时超额开仓。
|
||||
|
||||
### 5. 监控与统计(用现有接口即可)
|
||||
|
||||
- **按平仓时间统计**:已实现「按平仓时间」筛选与统计,可看**每日/每周「平仓笔数、平仓盈亏」**,区分「开仓日」与「平仓日」表现。
|
||||
- **按标的/按方向**:统计哪些 symbol、多/空在低量期亏损集中,用于**黑名单或降权**(例如某几类币在低量期一律不开或只做一侧)。
|
||||
|
||||
---
|
||||
|
||||
## 五、小结与建议顺序
|
||||
|
||||
- **可能原因**:成交量低 → 滑点大、费率占比高、假突破多、止盈难触发而止损/横盘小亏多;若再叠加多空结构不利,会放大「稳定小亏」。
|
||||
- **文档利用**:你已有的行情 REST/WS、订单与条件单推送、WS 交易、用户余额与账户流,**足够**支撑:流动性过滤、资金费率/多空过滤、跟踪止损与时间止损、按保证金控仓、以及统计与监控。
|
||||
- **建议实施顺序**:
|
||||
1. 加强**成交量/深度过滤**(扫描 + 开仓前检查);
|
||||
2. 略**收紧资金费率**阈值、保持或略加强扫描阶段费率过滤;
|
||||
3. 上**跟踪止损**与**时间/无盈利止损**;
|
||||
4. 低量期**降频、降单笔仓位**,并用余额/账户流做风控;
|
||||
5. 用**按平仓时间统计**与条件单推送,持续观察「谁在亏、因何平仓」,再微调标的与参数。
|
||||
|
||||
如需,我可以按上述某一条(例如「开仓前深度检查」或「时间止损参数」)写出具体实现步骤或伪代码,直接对接到你现有 `market_scanner` / `strategy` / `position_manager`。
|
||||
|
|
@ -242,6 +242,19 @@ DEFAULT_TRADING_CONFIG = {
|
|||
# 扫描阶段资金费率过滤:排除 |lastFundingRate| 过大的标的,避免进入 TOP_N
|
||||
'SCAN_FUNDING_RATE_FILTER_ENABLED': True,
|
||||
'SCAN_FUNDING_RATE_MAX_ABS': 0.001, # 绝对值超过 0.1% 则从扫描候选剔除
|
||||
# ===== 市场节奏自动识别(低波动期 vs 正常期,自动切换参数,无需手动)=====
|
||||
'MARKET_REGIME_AUTO': True, # 是否根据波动率自动识别并切换低波动期参数
|
||||
'LOW_VOLATILITY_THRESHOLD': 2.5, # 24h |changePercent| 中位数低于此值判为低波动期(%)
|
||||
'LOW_VOLATILITY_MAX_POSITION_PERCENT': 0.15, # 低波动期单币最大仓位(正常期用 MAX_POSITION_PERCENT)
|
||||
'LOW_VOLATILITY_MIN_SIGNAL_STRENGTH': 9, # 低波动期信号强度门槛(更严)
|
||||
'LOW_VOLATILITY_SCAN_FUNDING_RATE_MAX_ABS': 0.0005, # 低波动期扫描阶段资金费率更严(0.05%)
|
||||
'TIME_STOP_MAX_HOLD_HOURS': 8, # 持仓超过 N 小时且未达最小盈利则考虑平仓(低波动期更适用)
|
||||
'TIME_STOP_MIN_PNL_PCT_TO_HOLD': 0.0, # 持仓超过时间阈值时,若 pnl% 低于此值则平仓(0=允许小亏即走)
|
||||
'TIME_STOP_ENABLED': True, # 是否启用时间/无盈利止损(可与 regime 结合:仅低波动期或始终启用)
|
||||
# 开仓前流动性检查(价差/深度):低量期可减少滑点与冲击成本
|
||||
'LIQUIDITY_CHECK_BEFORE_ENTRY': False, # 默认关闭;开启后开仓前检查盘口价差与深度,不通过则跳过
|
||||
'LIQUIDITY_MAX_SPREAD_PCT': 0.005, # 买一卖一价差超过此比例(0.5%)则跳过
|
||||
'LIQUIDITY_MIN_DEPTH_USDT': 30000, # 前 5 档买卖深度合计名义价值低于此值(USDT)则跳过
|
||||
# 主动买卖量过滤(可选):与方向一致时通过,极端反向时跳过
|
||||
'TAKER_RATIO_FILTER_ENABLED': False, # 默认关闭,开启后做多要求 buySellRatio≥下限、做空要求≤上限
|
||||
'MIN_TAKER_BUY_RATIO_FOR_LONG': 0.85, # 做多时最近1h buySellRatio 低于此值则跳过(主动买不足)
|
||||
|
|
@ -369,6 +382,20 @@ for key, value in DEFAULT_TRADING_CONFIG.items():
|
|||
if key not in TRADING_CONFIG:
|
||||
TRADING_CONFIG[key] = value
|
||||
|
||||
|
||||
def get_effective_config(key: str, default=None):
|
||||
"""
|
||||
按当前市场节奏返回有效配置:若 MARKET_REGIME_AUTO 且为低波动期,
|
||||
则返回 LOW_VOLATILITY_<key>(若存在),否则返回 TRADING_CONFIG[key]。
|
||||
用于仓位、信号门槛、资金费率阈值、时间止损等,实现自动把握市场节奏。
|
||||
"""
|
||||
try:
|
||||
from . import market_regime
|
||||
return market_regime.get_effective_config(key, default)
|
||||
except ImportError:
|
||||
return TRADING_CONFIG.get(key, default)
|
||||
|
||||
|
||||
# 提供一个函数来重新加载配置
|
||||
def reload_config():
|
||||
"""重新加载配置(供外部调用)"""
|
||||
|
|
|
|||
122
trading_system/market_regime.py
Normal file
122
trading_system/market_regime.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
"""
|
||||
市场节奏自动识别:根据当前波动率/成交量判断「低波动期」与「正常期」,
|
||||
并自动切换参数(仓位、信号门槛、资金费率阈值、时间止损等),无需手动切换。
|
||||
"""
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional, Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
REDIS_KEY_REGIME = "market_regime"
|
||||
REDIS_KEY_UPDATED_AT = "market_regime_updated_at"
|
||||
REGIME_LOW = "low_volatility"
|
||||
REGIME_NORMAL = "normal"
|
||||
TTL_SEC = 3600 # 1 小时内无更新则视为过期,策略侧回退为 normal
|
||||
|
||||
|
||||
def _get_redis():
|
||||
"""获取 Redis 客户端(与 binance_client 一致)。"""
|
||||
try:
|
||||
from . import config
|
||||
from .redis_cache import RedisCache
|
||||
rc = RedisCache(
|
||||
redis_url=getattr(config, "REDIS_URL", "redis://localhost:6379"),
|
||||
use_tls=getattr(config, "REDIS_USE_TLS", False),
|
||||
ssl_cert_reqs=getattr(config, "REDIS_SSL_CERT_REQS", "required"),
|
||||
ssl_ca_certs=getattr(config, "REDIS_SSL_CA_CERTS", None),
|
||||
username=getattr(config, "REDIS_USERNAME", None),
|
||||
password=getattr(config, "REDIS_PASSWORD", None),
|
||||
)
|
||||
return rc
|
||||
except Exception as e:
|
||||
logger.debug("market_regime Redis 不可用: %s", e)
|
||||
return None
|
||||
|
||||
|
||||
async def update_regime_from_scan(
|
||||
change_percents: list,
|
||||
redis_cache: Any = None,
|
||||
low_volatility_threshold: float = 2.5,
|
||||
) -> str:
|
||||
"""
|
||||
根据本次扫描得到的 24h 涨跌幅列表,计算中位数绝对波动,更新市场节奏并写入 Redis。
|
||||
change_percents: 各 symbol 的 24h changePercent 列表(可含正负)
|
||||
返回当前写入的 regime:low_volatility 或 normal。
|
||||
"""
|
||||
if not change_percents:
|
||||
return REGIME_NORMAL
|
||||
abs_changes = [abs(float(x)) for x in change_percents if x is not None]
|
||||
if not abs_changes:
|
||||
return REGIME_NORMAL
|
||||
abs_changes.sort()
|
||||
n = len(abs_changes)
|
||||
median_abs = abs_changes[n // 2] if n % 2 else (abs_changes[n // 2 - 1] + abs_changes[n // 2]) / 2
|
||||
regime = REGIME_LOW if median_abs < low_volatility_threshold else REGIME_NORMAL
|
||||
cache = redis_cache or _get_redis()
|
||||
if cache:
|
||||
try:
|
||||
await cache.connect()
|
||||
await cache.set(REDIS_KEY_REGIME, regime, ttl=TTL_SEC)
|
||||
await cache.set(REDIS_KEY_UPDATED_AT, str(int(time.time())), ttl=TTL_SEC)
|
||||
logger.info(f"市场节奏: median_24h_change={median_abs:.2f}% -> {regime} (阈值={low_volatility_threshold}%)")
|
||||
except Exception as e:
|
||||
logger.debug("写入 market_regime 失败: %s", e)
|
||||
return regime
|
||||
|
||||
|
||||
async def get_regime(redis_cache: Any = None) -> str:
|
||||
"""从 Redis 读取当前市场节奏;无或过期则返回 normal。"""
|
||||
cache = redis_cache or _get_redis()
|
||||
if not cache:
|
||||
return REGIME_NORMAL
|
||||
try:
|
||||
await cache.connect()
|
||||
r = await cache.get(REDIS_KEY_REGIME)
|
||||
if r in (REGIME_LOW, REGIME_NORMAL):
|
||||
return r
|
||||
ts = await cache.get(REDIS_KEY_UPDATED_AT)
|
||||
if ts and (time.time() - int(ts)) > TTL_SEC:
|
||||
return REGIME_NORMAL
|
||||
except Exception as e:
|
||||
logger.debug("读取 market_regime 失败: %s", e)
|
||||
return REGIME_NORMAL
|
||||
|
||||
|
||||
def get_effective_config(key: str, default: Any = None, account_id: int = None) -> Any:
|
||||
"""
|
||||
根据当前市场节奏返回「有效配置」:若开启自动节奏且当前为低波动期,
|
||||
则优先返回 LOW_VOLATILITY_<key>,否则返回 TRADING_CONFIG[key]。
|
||||
用于仓位、信号门槛、资金费率阈值、时间止损等。
|
||||
"""
|
||||
try:
|
||||
from . import config
|
||||
except ImportError:
|
||||
import config
|
||||
cfg = getattr(config, "TRADING_CONFIG", None) or {}
|
||||
auto = cfg.get("MARKET_REGIME_AUTO")
|
||||
if not auto:
|
||||
return cfg.get(key, default)
|
||||
low_key = f"LOW_VOLATILITY_{key}"
|
||||
if low_key not in cfg:
|
||||
return cfg.get(key, default)
|
||||
# 同步读 Redis 会阻塞;这里用缓存避免每次读 Redis。策略层在每轮扫描后已更新 regime,本进程内可用内存缓存
|
||||
regime = _cached_regime
|
||||
if regime == REGIME_LOW:
|
||||
val = cfg.get(low_key)
|
||||
if val is not None:
|
||||
return val
|
||||
return cfg.get(key, default)
|
||||
|
||||
|
||||
# 进程内缓存:由扫描器在每次 scan 结束后异步更新,get_effective_config 同步读
|
||||
_cached_regime: str = REGIME_NORMAL
|
||||
|
||||
|
||||
def set_cached_regime(regime: str) -> None:
|
||||
global _cached_regime
|
||||
_cached_regime = regime if regime in (REGIME_LOW, REGIME_NORMAL) else REGIME_NORMAL
|
||||
|
||||
|
||||
def get_cached_regime() -> str:
|
||||
return _cached_regime
|
||||
|
|
@ -120,9 +120,9 @@ class MarketScanner:
|
|||
|
||||
logger.info(f"初步筛选后,需要详细分析的交易对: {len(pre_filtered_symbols)} 个")
|
||||
|
||||
# 扫描阶段资金费率过滤:排除 |lastFundingRate| 过大的标的(文档建议的后续方向)
|
||||
# 扫描阶段资金费率过滤:排除 |lastFundingRate| 过大的标的;低波动期使用更严阈值(有效配置)
|
||||
scan_funding_enabled = cfg.get('SCAN_FUNDING_RATE_FILTER_ENABLED', False)
|
||||
scan_funding_max_abs = float(cfg.get('SCAN_FUNDING_RATE_MAX_ABS', 0.001))
|
||||
scan_funding_max_abs = float(config.get_effective_config('SCAN_FUNDING_RATE_MAX_ABS', 0.001))
|
||||
if scan_funding_enabled and pre_filtered_symbols:
|
||||
try:
|
||||
premium_all = await self.client.get_premium_index(None) # 全量,一次请求
|
||||
|
|
@ -228,6 +228,21 @@ class MarketScanner:
|
|||
|
||||
self.top_symbols = top_n
|
||||
|
||||
# 市场节奏自动识别:用本次扫描的 24h 涨跌幅中位数判断低波动/正常,写入 Redis 并更新进程内缓存
|
||||
try:
|
||||
from . import market_regime
|
||||
except ImportError:
|
||||
market_regime = None
|
||||
if market_regime and getattr(self.client, "redis_cache", None):
|
||||
# 用过滤后的全部结果计算中位数(样本更多),无则用 top_n
|
||||
source = filtered_results if filtered_results else top_n
|
||||
change_percents = [r["changePercent"] for r in source if r.get("changePercent") is not None]
|
||||
threshold = float(cfg.get("LOW_VOLATILITY_THRESHOLD", config.TRADING_CONFIG.get("LOW_VOLATILITY_THRESHOLD", 2.5)))
|
||||
regime = await market_regime.update_regime_from_scan(
|
||||
change_percents, self.client.redis_cache, low_volatility_threshold=threshold
|
||||
)
|
||||
market_regime.set_cached_regime(regime)
|
||||
|
||||
# ⚠️ 已禁用扫描结果缓存,确保每个账户都使用最新的市场数据
|
||||
# 虽然中间数据(K线、技术指标)已经缓存,但最终扫描结果不缓存
|
||||
# 这样可以避免使用过期的交易对,确保每个账户都基于最新市场数据扫描
|
||||
|
|
|
|||
|
|
@ -3835,6 +3835,32 @@ class PositionManager:
|
|||
except Exception as e:
|
||||
logger.debug(f"从Redis重新加载配置失败: {e}")
|
||||
|
||||
# 时间/无盈利止损:持仓超过 N 小时且盈利未达阈值则平仓(低波动期减少磨单)
|
||||
time_stop_enabled = config.TRADING_CONFIG.get('TIME_STOP_ENABLED', False)
|
||||
if time_stop_enabled:
|
||||
max_hold_hours = float(config.get_effective_config('TIME_STOP_MAX_HOLD_HOURS', 8) or 8)
|
||||
min_pnl_to_hold = float(config.TRADING_CONFIG.get('TIME_STOP_MIN_PNL_PCT_TO_HOLD', 0.0) or 0.0)
|
||||
entry_time = position_info.get('entryTime')
|
||||
hold_hours = 0.0
|
||||
if entry_time:
|
||||
try:
|
||||
if isinstance(entry_time, datetime):
|
||||
hold_hours = (get_beijing_time() - entry_time).total_seconds() / 3600.0
|
||||
elif isinstance(entry_time, str):
|
||||
entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S')
|
||||
hold_hours = (get_beijing_time() - entry_dt).total_seconds() / 3600.0
|
||||
else:
|
||||
hold_hours = (time.time() - (float(entry_time) if isinstance(entry_time, (int, float)) else 0)) / 3600.0
|
||||
except Exception as e:
|
||||
logger.debug(f"{symbol} 解析 entryTime 失败: {e}")
|
||||
if hold_hours >= max_hold_hours and pnl_percent_margin < min_pnl_to_hold:
|
||||
logger.info(
|
||||
f"{symbol} [时间止损] 持仓 {hold_hours:.1f}h >= {max_hold_hours}h 且盈亏 {pnl_percent_margin:.2f}% < {min_pnl_to_hold}%,平仓"
|
||||
)
|
||||
if await self.close_position(symbol, reason='time_stop'):
|
||||
logger.info(f"{symbol} [时间止损] 平仓成功")
|
||||
return
|
||||
|
||||
# ⚠️ 优化:已完全移除时间锁限制
|
||||
# 理由:1) 止损和止盈都应该立即执行,不受时间限制
|
||||
# 2) 交易所级别的止损/止盈单已提供保护
|
||||
|
|
|
|||
|
|
@ -96,9 +96,10 @@ class RiskManager:
|
|||
margin_value = notional_value / actual_leverage
|
||||
|
||||
# 重要语义:POSITION_PERCENT 均按“保证金占用比例”计算(更符合 stop_loss/take_profit 的 margin 逻辑)
|
||||
max_margin_value = available_balance * config.TRADING_CONFIG['MAX_POSITION_PERCENT']
|
||||
max_position_pct = config.get_effective_config('MAX_POSITION_PERCENT', 0.20)
|
||||
max_margin_value = available_balance * max_position_pct
|
||||
min_margin_value = available_balance * config.TRADING_CONFIG['MIN_POSITION_PERCENT']
|
||||
max_margin_pct = config.TRADING_CONFIG['MAX_POSITION_PERCENT'] * 100
|
||||
max_margin_pct = max_position_pct * 100
|
||||
min_margin_pct = config.TRADING_CONFIG['MIN_POSITION_PERCENT'] * 100
|
||||
|
||||
logger.info(f" 数量: {quantity:.4f}")
|
||||
|
|
@ -593,8 +594,8 @@ class RiskManager:
|
|||
logger.info(f" 名义价值: {notional_value:.2f} USDT")
|
||||
logger.info(f" 保证金: {margin_value:.4f} USDT ({margin_value/total_balance*100:.2f}%)")
|
||||
|
||||
# 检查是否超过最大仓位限制
|
||||
max_position_percent = config.TRADING_CONFIG['MAX_POSITION_PERCENT']
|
||||
# 检查是否超过最大仓位限制(低波动期自动降低单笔上限)
|
||||
max_position_percent = config.get_effective_config('MAX_POSITION_PERCENT', 0.20)
|
||||
|
||||
# ⚠️ 如果启用了固定风险模型,且计算出的仓位合理(风险可控),则放宽 MAX_POSITION_PERCENT 限制
|
||||
# 因为固定风险模型的核心是控制亏损额,而不是仓位大小
|
||||
|
|
@ -640,8 +641,9 @@ class RiskManager:
|
|||
logger.info(f" ✓ 信号强度{signal_strength}分,使用100%仓位(高质量信号)")
|
||||
|
||||
# 根据涨跌幅调整仓位大小(涨跌幅越大,保证金占比可以适当增加)
|
||||
base_position_percent = config.TRADING_CONFIG['MAX_POSITION_PERCENT'] * signal_multiplier
|
||||
max_position_percent = config.TRADING_CONFIG['MAX_POSITION_PERCENT'] * signal_multiplier
|
||||
effective_max = config.get_effective_config('MAX_POSITION_PERCENT', 0.20)
|
||||
base_position_percent = effective_max * signal_multiplier
|
||||
max_position_percent = effective_max * signal_multiplier
|
||||
min_position_percent = config.TRADING_CONFIG['MIN_POSITION_PERCENT']
|
||||
|
||||
# 涨跌幅超过5%时,可以适当增加保证金占比,但必须遵守 MAX_POSITION_PERCENT 上限
|
||||
|
|
@ -717,7 +719,7 @@ class RiskManager:
|
|||
max_position_percent = 0.95
|
||||
max_margin_value = available_balance * 0.95
|
||||
else:
|
||||
max_position_percent = config.TRADING_CONFIG['MAX_POSITION_PERCENT']
|
||||
max_position_percent = config.get_effective_config('MAX_POSITION_PERCENT', 0.20)
|
||||
max_margin_value = available_balance * max_position_percent
|
||||
|
||||
if min_margin_usdt <= max_margin_value:
|
||||
|
|
@ -761,7 +763,7 @@ class RiskManager:
|
|||
quantity = quantity * position_scale
|
||||
final_notional_value = quantity * current_price
|
||||
final_margin = final_notional_value / actual_leverage if actual_leverage > 0 else final_notional_value
|
||||
max_margin_cap = available_balance * config.TRADING_CONFIG.get('MAX_POSITION_PERCENT', 0.08)
|
||||
max_margin_cap = available_balance * config.get_effective_config('MAX_POSITION_PERCENT', 0.20)
|
||||
if final_margin > max_margin_cap:
|
||||
final_margin = max_margin_cap
|
||||
final_notional_value = final_margin * actual_leverage
|
||||
|
|
|
|||
|
|
@ -196,6 +196,10 @@ class TradingStrategy:
|
|||
if not await self._check_taker_ratio_filter(symbol, trade_direction):
|
||||
logger.info(f"{symbol} 主动买卖量过滤未通过,跳过开仓")
|
||||
continue
|
||||
# 开仓前流动性检查(可选):价差/深度不达标则跳过,低量期减少滑点
|
||||
if not await self._check_liquidity_before_entry(symbol, symbol_info.get('price')):
|
||||
logger.info(f"{symbol} 流动性检查未通过,跳过开仓")
|
||||
continue
|
||||
entry_reason = trade_signal['reason']
|
||||
|
||||
signal_strength = trade_signal.get('strength', 0)
|
||||
|
|
@ -430,6 +434,48 @@ class TradingStrategy:
|
|||
logger.debug(f"{symbol} 主动买卖量检查失败(放行): {e}")
|
||||
return True
|
||||
|
||||
async def _check_liquidity_before_entry(self, symbol: str, current_price: Optional[float] = None) -> bool:
|
||||
"""
|
||||
开仓前流动性检查:盘口价差过大或深度过薄则跳过,减少低量期滑点与冲击成本。
|
||||
依赖 get_depth(symbol, limit=10),检查买一卖一价差与前 5 档深度(USDT)。
|
||||
"""
|
||||
enabled = bool(config.TRADING_CONFIG.get('LIQUIDITY_CHECK_BEFORE_ENTRY', False))
|
||||
if not enabled:
|
||||
return True
|
||||
try:
|
||||
depth = await self.client.get_depth(symbol, limit=10)
|
||||
if not depth or not isinstance(depth, dict):
|
||||
return True
|
||||
bids = depth.get('bids') or []
|
||||
asks = depth.get('asks') or []
|
||||
if not bids or not asks:
|
||||
logger.info(f"{symbol} 流动性检查:深度为空,跳过开仓")
|
||||
return False
|
||||
bid1_p = float(bids[0][0])
|
||||
ask1_p = float(asks[0][0])
|
||||
mid = (bid1_p + ask1_p) / 2.0
|
||||
if mid <= 0:
|
||||
return True
|
||||
spread_pct = (ask1_p - bid1_p) / mid
|
||||
max_spread = float(config.TRADING_CONFIG.get('LIQUIDITY_MAX_SPREAD_PCT', 0.005))
|
||||
if spread_pct > max_spread:
|
||||
logger.info(f"{symbol} 流动性检查:价差 {spread_pct*100:.3f}% > {max_spread*100:.2f}%,跳过开仓")
|
||||
return False
|
||||
# 前 5 档深度名义价值(USDT)
|
||||
depth_usdt = 0.0
|
||||
for i, (p, q) in enumerate(bids[:5]):
|
||||
depth_usdt += float(p) * float(q)
|
||||
for i, (p, q) in enumerate(asks[:5]):
|
||||
depth_usdt += float(p) * float(q)
|
||||
min_depth = float(config.TRADING_CONFIG.get('LIQUIDITY_MIN_DEPTH_USDT', 30000))
|
||||
if depth_usdt < min_depth:
|
||||
logger.info(f"{symbol} 流动性检查:前5档深度 {depth_usdt:.0f} USDT < {min_depth:.0f},跳过开仓")
|
||||
return False
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.debug(f"{symbol} 流动性检查失败(放行): {e}")
|
||||
return True
|
||||
|
||||
async def _check_volume_confirmation(self, symbol_info: Dict) -> bool:
|
||||
"""
|
||||
成交量确认 - 确保有足够的成交量支撑
|
||||
|
|
@ -595,8 +641,8 @@ class TradingStrategy:
|
|||
signal_strength = 0
|
||||
reasons.append("❌ 逆4H趋势,拒绝交易")
|
||||
|
||||
# 判断是否应该交易(信号强度 >= MIN_SIGNAL_STRENGTH 才交易,提高胜率)
|
||||
min_signal_strength = config.TRADING_CONFIG.get('MIN_SIGNAL_STRENGTH', 7)
|
||||
# 判断是否应该交易(信号强度 >= 有效 MIN_SIGNAL_STRENGTH 才交易;低波动期自动提高门槛)
|
||||
min_signal_strength = config.get_effective_config('MIN_SIGNAL_STRENGTH', 7)
|
||||
# 强度上限归一到 0-10,避免出现 12/10 这种误导显示
|
||||
try:
|
||||
signal_strength = max(0, min(int(signal_strength), 10))
|
||||
|
|
|
|||
|
|
@ -1,870 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": 5110,
|
||||
"symbol": "1000BONKUSDT",
|
||||
"side": "BUY",
|
||||
"quantity": 3531,
|
||||
"entry_price": 0.006565,
|
||||
"entry_value_usdt": 23.181015,
|
||||
"notional_usdt": 23.459964,
|
||||
"margin_usdt": 5.864991,
|
||||
"original_notional_usdt": 23.181015,
|
||||
"original_margin_usdt": 5.79525375,
|
||||
"mark_price": 0.006644,
|
||||
"pnl": 0.278949,
|
||||
"pnl_percent": 4.7561709813365445,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771214454,
|
||||
"stop_loss_price": 0.00636805,
|
||||
"take_profit_price": 0.00697531,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": null,
|
||||
"entry_order_type": null,
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460584754,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "SELL",
|
||||
"stopPrice": 0.006975,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584735,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "SELL",
|
||||
"stopPrice": 0.006369,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 0.006369 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.006975 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460584754,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "SELL",
|
||||
"stopPrice": 0.006975,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584735,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "SELL",
|
||||
"stopPrice": 0.006369,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5157,
|
||||
"symbol": "ZECUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 0.077,
|
||||
"entry_price": 284.54,
|
||||
"entry_value_usdt": 21.909580000000002,
|
||||
"notional_usdt": 22.23683,
|
||||
"margin_usdt": 5.5592075,
|
||||
"original_notional_usdt": 21.92881912,
|
||||
"original_margin_usdt": 5.48220478,
|
||||
"mark_price": 288.79,
|
||||
"pnl": -0.32725,
|
||||
"pnl_percent": -5.886630423491117,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771226616,
|
||||
"stop_loss_price": null,
|
||||
"take_profit_price": null,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": 14.62428571,
|
||||
"entry_order_id": 797717260491,
|
||||
"entry_order_type": "LIMIT",
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460584806,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 266.76,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584795,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 293.07,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 293.07 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 266.76 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460584806,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 266.76,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584795,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 293.07,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5109,
|
||||
"symbol": "HYPEUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 0.7,
|
||||
"entry_price": 30.158,
|
||||
"entry_value_usdt": 21.110599999999998,
|
||||
"notional_usdt": 20.984715002999998,
|
||||
"margin_usdt": 5.2461787507499995,
|
||||
"original_notional_usdt": 21.1106,
|
||||
"original_margin_usdt": 5.27765,
|
||||
"mark_price": 29.97816429,
|
||||
"pnl": 0.12588499,
|
||||
"pnl_percent": 2.3995558668679244,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771214453,
|
||||
"stop_loss_price": null,
|
||||
"take_profit_price": null,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": 5837357832,
|
||||
"entry_order_type": "LIMIT",
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460584837,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 28.274,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584833,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 31.062,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 31.062 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 28.274 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460584837,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 28.274,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584833,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 31.062,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5112,
|
||||
"symbol": "FILUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 22,
|
||||
"entry_price": 0.963,
|
||||
"entry_value_usdt": 21.186,
|
||||
"notional_usdt": 21.37234946,
|
||||
"margin_usdt": 5.343087365,
|
||||
"original_notional_usdt": 21.186,
|
||||
"original_margin_usdt": 5.2965,
|
||||
"mark_price": 0.97147043,
|
||||
"pnl": -0.18634946,
|
||||
"pnl_percent": -3.4876738348073033,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771214455,
|
||||
"stop_loss_price": 0.99189,
|
||||
"take_profit_price": 0.9028125,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": null,
|
||||
"entry_order_type": null,
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460584866,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.903,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584857,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.991,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 0.991 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.903 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460584866,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.903,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584857,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.991,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5113,
|
||||
"symbol": "TAKEUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 172,
|
||||
"entry_price": 0.03629,
|
||||
"entry_value_usdt": 6.24188,
|
||||
"notional_usdt": 5.387599,
|
||||
"margin_usdt": 5.387599,
|
||||
"original_notional_usdt": 6.24188,
|
||||
"original_margin_usdt": 6.24188,
|
||||
"mark_price": 0.03132325,
|
||||
"pnl": 0.854281,
|
||||
"pnl_percent": 15.856432522168037,
|
||||
"leverage": 1,
|
||||
"entry_time": 1771214456,
|
||||
"stop_loss_price": 0.0373787,
|
||||
"take_profit_price": 0.0272175,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": null,
|
||||
"entry_order_type": null,
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460584904,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.02722,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584895,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.03737,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 0.03737 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.02722 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460584904,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.02722,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584895,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.03737,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5135,
|
||||
"symbol": "ZROUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 13.5,
|
||||
"entry_price": 1.6807,
|
||||
"entry_value_usdt": 22.68945,
|
||||
"notional_usdt": 22.76581086,
|
||||
"margin_usdt": 5.691452715,
|
||||
"original_notional_usdt": 22.68945,
|
||||
"original_margin_usdt": 5.6723625,
|
||||
"mark_price": 1.68635636,
|
||||
"pnl": -0.07636086,
|
||||
"pnl_percent": -1.3416760855932017,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771223082,
|
||||
"stop_loss_price": 1.731121,
|
||||
"take_profit_price": 1.57565625,
|
||||
"take_profit_1": 1.57565625,
|
||||
"take_profit_2": 1.49288286,
|
||||
"atr": 0.07825714,
|
||||
"entry_order_id": 6021914660,
|
||||
"entry_order_type": "LIMIT",
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460584948,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 1.4929,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584947,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 1.7311,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 1.7311 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 1.4929 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460584948,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 1.4929,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584947,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 1.7311,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5115,
|
||||
"symbol": "AXSUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 18,
|
||||
"entry_price": 1.388,
|
||||
"entry_value_usdt": 24.983999999999998,
|
||||
"notional_usdt": 24.42318858,
|
||||
"margin_usdt": 6.105797145,
|
||||
"original_notional_usdt": 24.984,
|
||||
"original_margin_usdt": 6.246,
|
||||
"mark_price": 1.35684381,
|
||||
"pnl": 0.56081142,
|
||||
"pnl_percent": 9.184900950390155,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771214457,
|
||||
"stop_loss_price": 1.42964,
|
||||
"take_profit_price": 1.30125,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": null,
|
||||
"entry_order_type": null,
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460584986,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 1.302,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584975,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 1.429,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 1.429 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 1.302 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460584986,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 1.302,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460584975,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 1.429,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5137,
|
||||
"symbol": "XLMUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 127,
|
||||
"entry_price": 0.16858,
|
||||
"entry_value_usdt": 21.409660000000002,
|
||||
"notional_usdt": 21.68884283,
|
||||
"margin_usdt": 5.4222107075,
|
||||
"original_notional_usdt": 21.40966,
|
||||
"original_margin_usdt": 5.352415,
|
||||
"mark_price": 0.17077829,
|
||||
"pnl": -0.27918283,
|
||||
"pnl_percent": -5.1488746022694105,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771223321,
|
||||
"stop_loss_price": 0.1736374,
|
||||
"take_profit_price": 0.15804375,
|
||||
"take_profit_1": 0.15804375,
|
||||
"take_profit_2": 0.15550343,
|
||||
"atr": 0.00544857,
|
||||
"entry_order_id": 20994894391,
|
||||
"entry_order_type": "LIMIT",
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460585021,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.15551,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460585020,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.17363,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 0.17363 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.15551 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460585021,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.15551,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460585020,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.17363,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5116,
|
||||
"symbol": "DASHUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 0.571,
|
||||
"entry_price": 37.25,
|
||||
"entry_value_usdt": 21.26975,
|
||||
"notional_usdt": 21.304009999999998,
|
||||
"margin_usdt": 5.3260024999999995,
|
||||
"original_notional_usdt": 21.26975,
|
||||
"original_margin_usdt": 5.3174375,
|
||||
"mark_price": 37.31,
|
||||
"pnl": -0.03426,
|
||||
"pnl_percent": -0.6432591798445457,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771214458,
|
||||
"stop_loss_price": 38.3675,
|
||||
"take_profit_price": 34.921875,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": null,
|
||||
"entry_order_type": null,
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460585100,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 34.93,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460585093,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 38.36,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 38.36 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 34.93 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460585100,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 34.93,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460585093,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 38.36,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5117,
|
||||
"symbol": "USELESSUSDT",
|
||||
"side": "BUY",
|
||||
"quantity": 150,
|
||||
"entry_price": 0.04083,
|
||||
"entry_value_usdt": 6.124499999999999,
|
||||
"notional_usdt": 7.085999999999999,
|
||||
"margin_usdt": 7.085999999999999,
|
||||
"original_notional_usdt": 6.1245,
|
||||
"original_margin_usdt": 6.1245,
|
||||
"mark_price": 0.04724,
|
||||
"pnl": 0.9615,
|
||||
"pnl_percent": 13.56900931414056,
|
||||
"leverage": 1,
|
||||
"entry_time": 1771214459,
|
||||
"stop_loss_price": 0.0396051,
|
||||
"take_profit_price": 0.0510375,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": null,
|
||||
"entry_order_type": null,
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460585145,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "SELL",
|
||||
"stopPrice": 0.05103,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460585138,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "SELL",
|
||||
"stopPrice": 0.03961,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 0.03961 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.05103 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460585145,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "SELL",
|
||||
"stopPrice": 0.05103,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460585138,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "SELL",
|
||||
"stopPrice": 0.03961,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5118,
|
||||
"symbol": "ENAUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 194,
|
||||
"entry_price": 0.1196,
|
||||
"entry_value_usdt": 23.2024,
|
||||
"notional_usdt": 23.53230864,
|
||||
"margin_usdt": 5.88307716,
|
||||
"original_notional_usdt": 23.2024,
|
||||
"original_margin_usdt": 5.8006,
|
||||
"mark_price": 0.12130056,
|
||||
"pnl": -0.32990864,
|
||||
"pnl_percent": -5.607756468725288,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771214460,
|
||||
"stop_loss_price": 0.123188,
|
||||
"take_profit_price": 0.112125,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": null,
|
||||
"entry_order_type": null,
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460585199,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.1122,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460585168,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.1231,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 0.1231 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.1122 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460585199,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.1122,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460585168,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.1231,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5151,
|
||||
"symbol": "WLFIUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 219,
|
||||
"entry_price": 0.1011,
|
||||
"entry_value_usdt": 22.1409,
|
||||
"notional_usdt": 22.23684171,
|
||||
"margin_usdt": 5.5592104275,
|
||||
"original_notional_usdt": 22.1409,
|
||||
"original_margin_usdt": 22.1409,
|
||||
"mark_price": 0.10153809,
|
||||
"pnl": -0.09594171,
|
||||
"pnl_percent": -1.7258154058245532,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771226264,
|
||||
"stop_loss_price": null,
|
||||
"take_profit_price": null,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": 2846730648,
|
||||
"entry_order_type": "LIMIT",
|
||||
"open_orders": [],
|
||||
"active_sl_orders": "",
|
||||
"active_tp_orders": "",
|
||||
"binance_open_orders_raw": []
|
||||
},
|
||||
{
|
||||
"id": 5123,
|
||||
"symbol": "WLDUSDT",
|
||||
"side": "SELL",
|
||||
"quantity": 56,
|
||||
"entry_price": 0.4028,
|
||||
"entry_value_usdt": 22.5568,
|
||||
"notional_usdt": 22.65973696,
|
||||
"margin_usdt": 5.66493424,
|
||||
"original_notional_usdt": 22.5568,
|
||||
"original_margin_usdt": 5.6392,
|
||||
"mark_price": 0.40463816,
|
||||
"pnl": -0.10293696,
|
||||
"pnl_percent": -1.8170901133002384,
|
||||
"leverage": 4,
|
||||
"entry_time": 1771214479,
|
||||
"stop_loss_price": 0.414884,
|
||||
"take_profit_price": 0.377625,
|
||||
"take_profit_1": null,
|
||||
"take_profit_2": null,
|
||||
"atr": null,
|
||||
"entry_order_id": null,
|
||||
"entry_order_type": null,
|
||||
"open_orders": [
|
||||
{
|
||||
"orderId": 2000000460523250,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.3777,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460523242,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.4148,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
],
|
||||
"active_sl_orders": "STOP_MARKET @ 0.4148 (NEW)",
|
||||
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.3777 (NEW)",
|
||||
"binance_open_orders_raw": [
|
||||
{
|
||||
"orderId": 2000000460523250,
|
||||
"type": "TAKE_PROFIT_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.3777,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
},
|
||||
{
|
||||
"orderId": 2000000460523242,
|
||||
"type": "STOP_MARKET",
|
||||
"side": "BUY",
|
||||
"stopPrice": 0.4148,
|
||||
"price": 0,
|
||||
"origType": "CONDITIONAL",
|
||||
"reduceOnly": true,
|
||||
"status": "NEW"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
Loading…
Reference in New Issue
Block a user