feat(market_cache): 引入市场数据缓存机制以优化API调用
在 `backend/database/models.py` 中新增 `MarketCache` 类,支持从数据库缓存交易对信息和资金费率,减少对币安API的调用频率。更新 `binance_client` 和 `market_scanner` 以优先从缓存读取数据,添加超时处理和重试机制,提升系统稳定性。同时,增强了资金费率和主动买卖量的过滤逻辑,确保在开仓前进行有效的风险控制。
This commit is contained in:
parent
43e993034f
commit
0fb42a5f24
13
backend/database/add_market_cache.sql
Normal file
13
backend/database/add_market_cache.sql
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
-- 市场缓存表:存放较固定的交易所数据(交易对信息、资金费率规则等),减少 API 调用
|
||||
-- 执行: mysql -u root -p auto_trade_sys < add_market_cache.sql
|
||||
|
||||
USE `auto_trade_sys`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `market_cache` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`cache_key` VARCHAR(128) NOT NULL COMMENT '如 exchange_info, funding_info',
|
||||
`cache_value` LONGTEXT NOT NULL COMMENT 'JSON 内容',
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY `uk_cache_key` (`cache_key`),
|
||||
INDEX `idx_updated_at` (`updated_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='市场数据缓存(交易对/费率规则等)';
|
||||
|
|
@ -360,6 +360,128 @@ class TradingConfig:
|
|||
return str(value)
|
||||
|
||||
|
||||
# 缓存键常量(与 market_cache 表配合使用)
|
||||
MARKET_CACHE_KEY_EXCHANGE_INFO = "exchange_info"
|
||||
MARKET_CACHE_KEY_FUNDING_INFO = "funding_info"
|
||||
|
||||
|
||||
class MarketCache:
|
||||
"""
|
||||
市场数据缓存:交易对信息(exchange_info)、资金费率规则(funding_info) 等较固定内容入库,
|
||||
减少对币安 API 的调用。trading_system 可优先从 DB 读取,过期或缺失时再拉 API 并回写。
|
||||
"""
|
||||
@staticmethod
|
||||
def _table_exists():
|
||||
try:
|
||||
db.execute_one("SELECT 1 FROM market_cache LIMIT 1")
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get(cache_key: str):
|
||||
"""获取缓存:返回 dict { cache_value: 解析后的对象, updated_at } 或 None。"""
|
||||
if not MarketCache._table_exists():
|
||||
return None
|
||||
try:
|
||||
row = db.execute_one(
|
||||
"SELECT cache_value, updated_at FROM market_cache WHERE cache_key = %s",
|
||||
(cache_key,),
|
||||
)
|
||||
if not row:
|
||||
return None
|
||||
raw = row.get("cache_value")
|
||||
updated_at = row.get("updated_at")
|
||||
if raw is None:
|
||||
return None
|
||||
try:
|
||||
value = json.loads(raw) if isinstance(raw, str) else raw
|
||||
except Exception:
|
||||
value = raw
|
||||
return {"cache_value": value, "updated_at": updated_at}
|
||||
except Exception as e:
|
||||
logger.debug("MarketCache.get %s: %s", cache_key, e)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def set(cache_key: str, value) -> bool:
|
||||
"""写入缓存,value 可为 dict/list(将序列化为 JSON)。"""
|
||||
if not MarketCache._table_exists():
|
||||
return False
|
||||
try:
|
||||
payload = json.dumps(value, ensure_ascii=False) if not isinstance(value, str) else value
|
||||
db.execute_update(
|
||||
"""INSERT INTO market_cache (cache_key, cache_value)
|
||||
VALUES (%s, %s)
|
||||
ON DUPLICATE KEY UPDATE cache_value = VALUES(cache_value), updated_at = CURRENT_TIMESTAMP""",
|
||||
(cache_key, payload),
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning("MarketCache.set %s: %s", cache_key, e)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get_exchange_info(max_age_seconds: int = 86400):
|
||||
"""
|
||||
获取缓存的 exchange_info(币安 GET /fapi/v1/exchangeInfo)。
|
||||
若缓存存在且 updated_at 在 max_age_seconds 内,返回解析后的 exchange_info 字典;
|
||||
否则返回 None(调用方应拉 API 并调用 set_exchange_info 回写)。
|
||||
"""
|
||||
out = MarketCache.get(MARKET_CACHE_KEY_EXCHANGE_INFO)
|
||||
if not out:
|
||||
return None
|
||||
updated_at = out.get("updated_at")
|
||||
if max_age_seconds is not None and updated_at:
|
||||
try:
|
||||
from datetime import datetime, timezone, timedelta
|
||||
if isinstance(updated_at, (int, float)):
|
||||
utc_ts = float(updated_at)
|
||||
else:
|
||||
# datetime 转 UTC 时间戳
|
||||
utc_ts = updated_at.timestamp() if hasattr(updated_at, "timestamp") else 0
|
||||
age = datetime.now(timezone.utc).timestamp() - utc_ts
|
||||
if age > max_age_seconds:
|
||||
return None
|
||||
except Exception:
|
||||
pass
|
||||
return out.get("cache_value")
|
||||
|
||||
@staticmethod
|
||||
def set_exchange_info(data: dict) -> bool:
|
||||
"""写入 exchange_info 到 market_cache。"""
|
||||
return MarketCache.set(MARKET_CACHE_KEY_EXCHANGE_INFO, data)
|
||||
|
||||
@staticmethod
|
||||
def get_funding_info(max_age_seconds: int = 86400):
|
||||
"""
|
||||
获取缓存的 funding_info(币安 GET /fapi/v1/fundingInfo)。
|
||||
若缓存存在且在 max_age_seconds 内,返回解析后的列表/字典;否则返回 None。
|
||||
"""
|
||||
out = MarketCache.get(MARKET_CACHE_KEY_FUNDING_INFO)
|
||||
if not out:
|
||||
return None
|
||||
updated_at = out.get("updated_at")
|
||||
if max_age_seconds is not None and updated_at:
|
||||
try:
|
||||
from datetime import datetime, timezone
|
||||
if isinstance(updated_at, (int, float)):
|
||||
utc_ts = float(updated_at)
|
||||
else:
|
||||
utc_ts = updated_at.timestamp() if hasattr(updated_at, "timestamp") else 0
|
||||
age = datetime.now(timezone.utc).timestamp() - utc_ts
|
||||
if age > max_age_seconds:
|
||||
return None
|
||||
except Exception:
|
||||
pass
|
||||
return out.get("cache_value")
|
||||
|
||||
@staticmethod
|
||||
def set_funding_info(data) -> bool:
|
||||
"""写入 funding_info 到 market_cache。"""
|
||||
return MarketCache.set(MARKET_CACHE_KEY_FUNDING_INFO, data)
|
||||
|
||||
|
||||
class GlobalStrategyConfig:
|
||||
"""全局策略配置模型(独立于账户,管理员专用)"""
|
||||
|
||||
|
|
|
|||
58
docs/后续方向实施说明.md
Normal file
58
docs/后续方向实施说明.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# 后续方向实施说明
|
||||
|
||||
本文档说明「策略与信号评估及改进建议」中未实现或部分实现的方向,以及固定内容入库的用法。
|
||||
|
||||
---
|
||||
|
||||
## 一、已完成的改动
|
||||
|
||||
### 1. 固定内容入库(交易对 / 费率规则)
|
||||
|
||||
- **表**:`market_cache`(见 `backend/database/add_market_cache.sql`)
|
||||
- 字段:`cache_key`(如 `exchange_info`、`funding_info`)、`cache_value`(JSON)、`updated_at`
|
||||
- **模型**:`backend/database/models.py` 中的 `MarketCache`
|
||||
- `get_exchange_info(max_age_seconds=86400)` / `set_exchange_info(data)`
|
||||
- `get_funding_info(max_age_seconds=86400)` / `set_funding_info(data)`
|
||||
- **使用**:`trading_system/binance_client.py`
|
||||
- `get_all_usdt_pairs()`:优先从 DB 读 `exchange_info`(24 小时内有效),命中则直接解析返回;否则请求 API 并回写 DB。
|
||||
- `get_symbol_info(symbol)`:在内存/Redis 未命中时,尝试从 DB 的 `exchange_info` 解析该 symbol;API 拉取后也会回写 DB。
|
||||
|
||||
**部署**:执行 `mysql -u root -p auto_trade_sys < backend/database/add_market_cache.sql` 创建表。无需改配置即可生效。
|
||||
|
||||
### 2. 扫描阶段资金费率过滤
|
||||
|
||||
- **配置**(`trading_system/config.py` 与 DB `trading_config`):
|
||||
- `SCAN_FUNDING_RATE_FILTER_ENABLED`:是否启用(默认 True)
|
||||
- `SCAN_FUNDING_RATE_MAX_ABS`:阈值,默认 0.001(即 \|lastFundingRate\| > 0.1% 的标的从扫描候选剔除)
|
||||
- **逻辑**:在 `market_scanner.scan_market()` 中,在得到「初步筛选后」的 `pre_filtered_symbols` 后,若启用则调用 `get_premium_index(None)` 取全量费率,剔除 \|lastFundingRate\| > 阈值的 symbol,再进入详细分析(K 线/技术指标)。
|
||||
|
||||
---
|
||||
|
||||
## 二、建议实现顺序(未实现部分)
|
||||
|
||||
| 顺序 | 方向 | 说明 |
|
||||
|------|----------------|------|
|
||||
| 1 | 跟踪止损 | 浮盈达到 X% 后,用 `TRAILING_STOP_MARKET` 替代或补充固定止盈;配置:`TRAILING_STOP_ENABLED`、`TRAILING_ACTIVATION_PCT`、`TRAILING_CALLBACK_RATE`;在 position_manager 挂完固定 SL/TP 后,达标则下跟踪止损单。 |
|
||||
| 2 | 时间/无盈利止损 | 持仓时长 > N 小时且浮盈 < 某阈值(或浮亏)→ 市价平仓或提高止损优先级;配置:`MAX_HOLD_HOURS`、`MIN_PNL_PCT_TO_HOLD`;在 position_manager 的检查循环里按 `entry_time` 与当前 pnl% 判断。 |
|
||||
| 3 | WS 订单/成交优化 | 下单后根据 ORDER_TRADE_UPDATE/TRADE 做快速反馈、部分成交后的加仓/减仓逻辑;实现成本较高,可排在跟踪止损和时间止损之后。 |
|
||||
|
||||
---
|
||||
|
||||
## 三、跟踪止损(待实现)要点
|
||||
|
||||
- **币安**:条件单类型 `TRAILING_STOP_MARKET`,需 `callbackRate`、`activationPrice`(或由系统按比例计算)。
|
||||
- **配置建议**:与现有 `USE_TRAILING_STOP`、`TRAILING_STOP_ACTIVATION`、`TRAILING_STOP_PROTECT` 对齐,或新增 `TRAILING_ACTIVATION_PCT`、`TRAILING_CALLBACK_RATE` 从 config/DB 读取。
|
||||
- **位置**:`trading_system/position_manager.py` 中,在挂完固定 SL/TP 后(或定时检查持仓时),若启用且当前浮盈% ≥ 激活比例,则下 `TRAILING_STOP_MARKET`;若已有跟踪止损单则跳过。
|
||||
|
||||
---
|
||||
|
||||
## 四、时间/无盈利止损(待实现)要点
|
||||
|
||||
- **逻辑**:在 position_manager 的持仓检查循环中,读取每仓的 `entry_time` 和当前 pnl%;若 `持仓时长 > MAX_HOLD_HOURS` 且 `pnl_percent < MIN_PNL_PCT_TO_HOLD`(或为负),则触发市价平仓或标记为「建议平仓」。
|
||||
- **配置**:`MAX_HOLD_HOURS`、`MIN_PNL_PCT_TO_HOLD`,从 config/DB 读。
|
||||
|
||||
---
|
||||
|
||||
## 五、手续费等固定费率(可选)
|
||||
|
||||
若后续要做「预估盈亏」或「最小盈利目标」,可将 maker/taker 费率存入 config 或单独表(如 `symbol_fee`),在算目标价/预期收益时读取。当前未实现。
|
||||
82
docs/策略与信号评估及改进建议.md
Normal file
82
docs/策略与信号评估及改进建议.md
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# 策略与信号评估及改进建议
|
||||
|
||||
基于持仓记录(2026-02-16)、当前策略逻辑与币安接口文档,对「长时间持仓、盈利不明显」做简要诊断,并给出可落地的改进方向。
|
||||
|
||||
---
|
||||
|
||||
## 一、持仓与信号现状简要诊断
|
||||
|
||||
### 1. 持仓样本(来自 持仓记录_2026-02-16)
|
||||
|
||||
- **数量**:约 12 个持仓,多空混合(BUY 少、SELL 多)。
|
||||
- **盈亏分布**:部分有 +15%、+13%、+9% 等浮盈,多数在 -5%~+2% 区间横盘,整体「拿得久、盈利不突出」。
|
||||
- **共性**:
|
||||
- 入场依赖 1H/4H 技术信号(MACD + EMA + 4H 趋势),**无资金费率、多空结构、订单流等过滤**,容易在「结构不利」时开仓。
|
||||
- 止损/止盈为固定比例或 ATR,**无跟踪止损、无时间止损**,盈利单容易回吐,亏损单容易长期挂单。
|
||||
- 选币主要按 24h 涨跌幅 + 成交量 + signal_strength 排序,**未用资金费率、大户多空比、主动买卖量等** 做过滤或排序。
|
||||
|
||||
### 2. 当前信号与选单逻辑(简要)
|
||||
|
||||
- **扫描**:24h 涨跌幅 ≥ 阈值 + 成交量 ≥ MIN_VOLUME_24H_STRICT → 对每个 symbol 拉 1H/4H K 线 → 算 RSI、MACD、EMA、4H 趋势 → 算 **signal_strength**(0–10),按强度排序取 TOP_N。
|
||||
- **开仓条件**:signal_strength ≥ MIN_SIGNAL_STRENGTH(8)、4H 趋势不逆势、RSI/24h 涨跌幅过滤、短周期方向过滤、大盘 Beta 过滤等。
|
||||
- **问题点**:
|
||||
- 信号完全来自 K 线技术指标,**没有合约特有的「成本与结构」信息**(资金费率、多空比、主动买卖)→ 容易在费率极高或多空极度拥挤时进场。
|
||||
- 入场时机只看扫描周期(如 15 分钟一次),**没有用 WS 订单/成交推送做更细的时机优化**。
|
||||
- 出场只有固定 SL/TP,**没有跟踪止损、没有「持仓时间 + 无盈利」类时间止损**。
|
||||
|
||||
---
|
||||
|
||||
## 二、基于现有接口的改进方向(可落地)
|
||||
|
||||
### 1. 资金费率过滤(已接入 REST,建议**优先上**)
|
||||
|
||||
- **接口**:`GET /fapi/v1/premiumIndex`(已封装为 `get_premium_index(symbol)`),含 `lastFundingRate`。
|
||||
- **思路**:
|
||||
- **做多**:若 `lastFundingRate > 某上限`(例如 0.001,即 0.1%),说明多头付费高,开多成本高、易被费率侵蚀 → **跳过开多**。
|
||||
- **做空**:若 `lastFundingRate < 某下限`(例如 -0.001),说明空头付费高 → **跳过开空**。
|
||||
- **效果**:减少在「费率极端不利于己方」时开仓,提高单笔期望收益;配合现有技术信号,不改变主逻辑,只做过滤。
|
||||
- **实现**:在策略层开仓前增加「资金费率过滤」步骤(见下节代码)。
|
||||
|
||||
### 2. 大户多空比 / 主动买卖量(已接入 REST,可选增强)
|
||||
|
||||
- **接口**:`get_top_long_short_position_ratio`、`get_taker_long_short_ratio`(或账户数多空比)。
|
||||
- **思路**:
|
||||
- **做多**:优先选择「近期主动买入占比高」或「大户多空比」偏多的标的(顺势);或极端多头拥挤时做「逆势空」需谨慎、可提高信号门槛。
|
||||
- **做空**:优先选择「主动卖出占比高」或大户偏空的标的。
|
||||
- **实现**:可在扫描后、或策略决定开仓前,对候选 symbol 取最近 1 条 taker 或大户多空比,与方向一致则通过、相反则降权或跳过(可选,先上资金费率再考虑)。
|
||||
|
||||
### 3. 订单/成交推送(WS)对「下单时机」的改进
|
||||
|
||||
- **文档**:订单交易更新推送(ORDER_TRADE_UPDATE)、条件单更新(ALGO_UPDATE)、账户信息流等。
|
||||
- **思路**:
|
||||
- 已有 User Data Stream 时,**订单状态、成交回报**已经实时;可在此基础上做「下单后快速反馈、部分成交/全部成交的后续动作」。
|
||||
- 若引入 **aggTrade / depth** 等行情 WS:可在「信号已满足」时,结合最近几笔大单或盘口变化再点一次火,减少「信号刚满足就追在尖顶/尖底」的情况(实现成本较高,可作为二期)。
|
||||
|
||||
### 4. 止盈/止损与持仓管理
|
||||
|
||||
- **跟踪止损**:文档支持 `TRAILING_STOP_MARKET`(激活价、回调比例)。可在「浮盈达到 X% 后」改为跟踪止损,锁定利润、让利润奔跑。
|
||||
- **时间止损**:若持仓超过 N 小时且浮盈 < 某阈值(或浮亏),可考虑平仓释放保证金,避免长期无效挂单(需在 position_manager 或策略层加「持仓时长」判断)。
|
||||
- **分批止盈**:当前有 take_profit_1/2 等设计;可结合 ATR 或固定比例,先平一部分、留一部分用跟踪止损(逻辑已有基础,可逐步细化)。
|
||||
|
||||
### 5. 扫描与选币
|
||||
|
||||
- **资金费率**:扫描阶段可排除「费率极端」的标的(例如 |lastFundingRate| > 0.001),避免进入 TOP_N 的 symbol 本身就不适合当前方向。
|
||||
- **成交量/流动性**:继续用 24h 成交量 + 深度(若有)保证可执行性;深度接口已接入,可用于大单前的冲击成本估算。
|
||||
- **多空比/主动买卖**:作为排序加分项(与方向一致则排前),而不是硬过滤,避免过度减少开仓次数。
|
||||
|
||||
---
|
||||
|
||||
## 三、建议实施顺序
|
||||
|
||||
1. **立即**:在开仓前增加**资金费率过滤**(做多/做空各一个阈值),并加配置开关与日志。
|
||||
2. **短期**:在配置中提供**跟踪止损**开关与参数(如激活盈利率、回调比例),对已有持仓在达到条件时切到跟踪止损(或先对部分新开仓做实验)。
|
||||
3. **中期**:在扫描或策略中引入**大户多空比 / taker 买卖比**,作为过滤或排序加分,并观察胜率与频率变化。
|
||||
4. **可选**:结合 WS 订单/成交与行情(aggTrade/depth)做更细的入场时机优化;以及「持仓时间 + 无盈利」的时间止损。
|
||||
|
||||
---
|
||||
|
||||
## 四、小结
|
||||
|
||||
- **现状**:信号与选单主要依赖 K 线技术指标和 4H 趋势,缺少「资金费率、多空结构、订单流」等维度,且出场方式单一,容易导致持仓时间长、盈利不明显。
|
||||
- **改进**:在**不推翻现有技术信号**的前提下,优先用**资金费率**做开仓过滤,再用**多空比/主动买卖**做过滤或排序,并逐步加上**跟踪止损**和**时间/无盈利止损**,有望在控制回撤的同时提高单笔质量与资金效率。
|
||||
- 上述改进均可基于你已接入的 REST 接口(premiumIndex、fundingRate、topLongShort、takerlongshortRatio 等)和现有 WS 文档实现;具体参数(费率阈值、跟踪止损比例等)可在实盘或回测中微调。
|
||||
|
|
@ -5,7 +5,9 @@ import asyncio
|
|||
import json
|
||||
import logging
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Any
|
||||
from binance import AsyncClient, BinanceSocketManager
|
||||
from binance.exceptions import BinanceAPIException
|
||||
|
|
@ -19,6 +21,92 @@ except ImportError:
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 交易对/费率等固定内容优先从 DB 读取(market_cache 表),减少 API 调用
|
||||
def _get_market_cache():
|
||||
"""延迟导入 MarketCache(需 backend 在 sys.path)。失败返回 None。"""
|
||||
try:
|
||||
backend_path = Path(__file__).resolve().parent.parent / "backend"
|
||||
if backend_path.exists() and str(backend_path) not in sys.path:
|
||||
sys.path.insert(0, str(backend_path))
|
||||
from database.models import MarketCache
|
||||
return MarketCache
|
||||
except Exception as e:
|
||||
logger.debug("MarketCache 不可用: %s", e)
|
||||
return None
|
||||
|
||||
|
||||
def _load_exchange_info_from_db(max_age_seconds: int = 86400):
|
||||
"""同步从 DB 读取 exchange_info(供 run_in_executor 调用)。"""
|
||||
mc = _get_market_cache()
|
||||
if not mc:
|
||||
return None
|
||||
return mc.get_exchange_info(max_age_seconds=max_age_seconds)
|
||||
|
||||
|
||||
def _save_exchange_info_to_db(data: dict) -> bool:
|
||||
"""同步将 exchange_info 写入 DB。"""
|
||||
mc = _get_market_cache()
|
||||
if not mc:
|
||||
return False
|
||||
return mc.set_exchange_info(data)
|
||||
|
||||
|
||||
def _parse_usdt_pairs_from_exchange_info(exchange_info: dict) -> tuple:
|
||||
"""从 exchange_info 解析 USDT 永续列表和 display_to_api 映射。返回 (usdt_pairs, display_to_api_symbol)."""
|
||||
if not exchange_info or not isinstance(exchange_info.get("symbols"), list):
|
||||
return [], {}
|
||||
usdt_pairs = []
|
||||
display_to_api = {}
|
||||
for s in exchange_info["symbols"]:
|
||||
if not (s.get("symbol", "").endswith("USDT") and s.get("status") == "TRADING" and s.get("contractType") == "PERPETUAL"):
|
||||
continue
|
||||
sym = s["symbol"]
|
||||
if sym.isascii():
|
||||
usdt_pairs.append(sym)
|
||||
continue
|
||||
api_sym = (s.get("baseAsset") or "") + (s.get("quoteAsset") or "")
|
||||
if api_sym and api_sym.isascii():
|
||||
usdt_pairs.append(api_sym)
|
||||
display_to_api[sym] = api_sym
|
||||
else:
|
||||
usdt_pairs.append(sym)
|
||||
return usdt_pairs, display_to_api
|
||||
|
||||
|
||||
def _parse_symbol_info_from_exchange_info(exchange_info: dict, symbol: str) -> Optional[Dict]:
|
||||
"""从 exchange_info 中解析单个 symbol 的精度/限制信息,与 get_symbol_info 返回格式一致。"""
|
||||
if not exchange_info or not isinstance(exchange_info.get("symbols"), list):
|
||||
return None
|
||||
for s in exchange_info["symbols"]:
|
||||
if s.get("symbol") != symbol:
|
||||
continue
|
||||
quantity_precision = s.get("quantityPrecision", 8)
|
||||
price_precision = s.get("pricePrecision", 8)
|
||||
min_qty, step_size, min_notional, tick_size = None, None, None, None
|
||||
for f in s.get("filters", []):
|
||||
if f.get("filterType") == "LOT_SIZE":
|
||||
min_qty = float(f.get("minQty", 0))
|
||||
step_size = float(f.get("stepSize", 0))
|
||||
elif f.get("filterType") == "PRICE_FILTER":
|
||||
tick_size = float(f.get("tickSize", 0) or 0)
|
||||
elif f.get("filterType") == "MIN_NOTIONAL":
|
||||
min_notional = float(f.get("notional", 0))
|
||||
if min_notional is None or min_notional == 0:
|
||||
min_notional = 5.0
|
||||
max_leverage_supported = 125
|
||||
if s.get("leverageBracket") and len(s.get("leverageBracket", [])) > 0:
|
||||
max_leverage_supported = s["leverageBracket"][0].get("maxLeverage", 125)
|
||||
return {
|
||||
"quantityPrecision": quantity_precision,
|
||||
"pricePrecision": price_precision,
|
||||
"minQty": min_qty or 0,
|
||||
"stepSize": step_size or 0,
|
||||
"tickSize": tick_size or 0,
|
||||
"minNotional": min_notional,
|
||||
"maxLeverage": int(max_leverage_supported),
|
||||
}
|
||||
return None
|
||||
|
||||
|
||||
def _format_exception(e: Exception) -> str:
|
||||
"""格式化异常用于日志,避免空 message 导致日志无内容"""
|
||||
|
|
@ -458,7 +546,8 @@ class BinanceClient:
|
|||
async def get_all_usdt_pairs(self, max_retries: int = 3, timeout: int = 30) -> List[str]:
|
||||
"""
|
||||
获取所有USDT交易对
|
||||
添加超时处理和重试机制,避免推荐系统因网络超时中断
|
||||
优先从 DB market_cache 读取 exchange_info(24 小时内有效),减少 API 调用。
|
||||
添加超时处理和重试机制,避免推荐系统因网络超时中断。
|
||||
|
||||
Args:
|
||||
max_retries: 最大重试次数(默认3次)
|
||||
|
|
@ -467,10 +556,24 @@ class BinanceClient:
|
|||
Returns:
|
||||
USDT交易对列表(失败时返回空列表)
|
||||
"""
|
||||
loop = asyncio.get_event_loop()
|
||||
# 优先从 DB 读取(同步调用放至线程池)
|
||||
try:
|
||||
exchange_info = await loop.run_in_executor(None, lambda: _load_exchange_info_from_db(86400))
|
||||
if exchange_info and isinstance(exchange_info.get("symbols"), list):
|
||||
usdt_pairs, display_to_api = _parse_usdt_pairs_from_exchange_info(exchange_info)
|
||||
if usdt_pairs:
|
||||
self._display_to_api_symbol.clear()
|
||||
self._display_to_api_symbol.update(display_to_api)
|
||||
if display_to_api:
|
||||
logger.info(f"已映射 {len(display_to_api)} 个中文/非ASCII交易对到英文 symbol")
|
||||
logger.info(f"从 DB 缓存获取到 {len(usdt_pairs)} 个USDT永续合约交易对")
|
||||
return usdt_pairs
|
||||
except Exception as e:
|
||||
logger.debug("从 DB 读取 exchange_info 失败,将请求 API: %s", e)
|
||||
|
||||
for attempt in range(1, max_retries + 1):
|
||||
try:
|
||||
# 使用 _rate_limited_request 包装请求,添加速率限制
|
||||
# 同时使用 asyncio.wait_for 添加超时处理
|
||||
exchange_info = await asyncio.wait_for(
|
||||
self._rate_limited_request(
|
||||
'futures_exchange_info',
|
||||
|
|
@ -478,35 +581,17 @@ class BinanceClient:
|
|||
),
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
# 支持中文名交易对:若 symbol 含非 ASCII,尝试用 baseAsset+quoteAsset 作为 API 下单用 symbol
|
||||
# 如果 baseAsset+quoteAsset 也是非 ASCII,则直接使用原始 symbol
|
||||
usdt_pairs, display_to_api = _parse_usdt_pairs_from_exchange_info(exchange_info)
|
||||
self._display_to_api_symbol.clear()
|
||||
usdt_pairs = []
|
||||
for s in exchange_info['symbols']:
|
||||
if not (s['symbol'].endswith('USDT') and s['status'] == 'TRADING' and s.get('contractType') == 'PERPETUAL'):
|
||||
continue
|
||||
sym = s['symbol']
|
||||
|
||||
# 1. 如果是 ASCII,直接使用
|
||||
if sym.isascii():
|
||||
usdt_pairs.append(sym)
|
||||
continue
|
||||
|
||||
# 2. 如果非 ASCII,尝试构建英文 symbol (base+quote)
|
||||
api_sym = (s.get('baseAsset') or '') + (s.get('quoteAsset') or '')
|
||||
if api_sym and api_sym.isascii():
|
||||
usdt_pairs.append(api_sym)
|
||||
self._display_to_api_symbol[sym] = api_sym
|
||||
logger.debug(f"交易对显示名 -> API symbol: '{sym}' -> '{api_sym}'")
|
||||
else:
|
||||
# 3. 如果 base+quote 也是非 ASCII(如 '币安人生USDT'),则直接使用原始 symbol
|
||||
# 用户反馈希望交易这些特殊币种
|
||||
usdt_pairs.append(sym)
|
||||
logger.info(f"添加非ASCII交易对: {sym!r} (baseAsset={s.get('baseAsset')!r})")
|
||||
if self._display_to_api_symbol:
|
||||
logger.info(f"已映射 {len(self._display_to_api_symbol)} 个中文/非ASCII交易对到英文 symbol,均可正常下单")
|
||||
self._display_to_api_symbol.update(display_to_api)
|
||||
if display_to_api:
|
||||
logger.info(f"已映射 {len(display_to_api)} 个中文/非ASCII交易对到英文 symbol,均可正常下单")
|
||||
logger.info(f"获取到 {len(usdt_pairs)} 个USDT永续合约交易对")
|
||||
# 回写 DB 供下次使用
|
||||
try:
|
||||
await loop.run_in_executor(None, lambda: _save_exchange_info_to_db(exchange_info))
|
||||
except Exception as e:
|
||||
logger.debug("exchange_info 写入 DB 失败: %s", e)
|
||||
return usdt_pairs
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
|
|
@ -1112,6 +1197,7 @@ class BinanceClient:
|
|||
交易对信息字典,包含 quantityPrecision, minQty, stepSize 等
|
||||
"""
|
||||
symbol = self._resolve_api_symbol(symbol)
|
||||
loop = asyncio.get_event_loop()
|
||||
# 1. 先检查内存缓存
|
||||
if symbol in self._symbol_info_cache:
|
||||
cached_mem = self._symbol_info_cache[symbol]
|
||||
|
|
@ -1133,11 +1219,23 @@ class BinanceClient:
|
|||
if isinstance(cached, dict) and ("tickSize" not in cached or "pricePrecision" not in cached):
|
||||
logger.info(f"{symbol} symbol_info 缓存缺少 tickSize/pricePrecision,自动刷新一次")
|
||||
else:
|
||||
# 同时更新内存缓存
|
||||
self._symbol_info_cache[symbol] = cached
|
||||
return cached
|
||||
|
||||
# 3. 缓存未命中,调用 API(加超时与重试,避免网络抖动导致开仓前获取交易对信息失败)
|
||||
|
||||
# 3. 尝试从 DB market_cache 读取 exchange_info 并解析本 symbol
|
||||
try:
|
||||
exchange_info_db = await loop.run_in_executor(None, lambda: _load_exchange_info_from_db(86400))
|
||||
info = _parse_symbol_info_from_exchange_info(exchange_info_db, symbol) if exchange_info_db else None
|
||||
if info:
|
||||
self._symbol_info_cache[symbol] = info
|
||||
if self.redis_cache:
|
||||
await self.redis_cache.set(cache_key, info, ttl=3600)
|
||||
logger.debug(f"从 DB 缓存解析 {symbol} 交易对信息")
|
||||
return info
|
||||
except Exception as e:
|
||||
logger.debug("从 DB 读取 exchange_info 解析 %s 失败: %s", symbol, e)
|
||||
|
||||
# 4. 缓存未命中,调用 API(加超时与重试)
|
||||
read_timeout = getattr(config, 'READ_ONLY_REQUEST_TIMEOUT', 60)
|
||||
last_err = None
|
||||
for attempt in range(3):
|
||||
|
|
@ -1146,6 +1244,11 @@ class BinanceClient:
|
|||
self.client.futures_exchange_info(),
|
||||
timeout=read_timeout
|
||||
)
|
||||
# 回写 DB 供后续请求使用
|
||||
try:
|
||||
await loop.run_in_executor(None, lambda: _save_exchange_info_to_db(exchange_info))
|
||||
except Exception as e:
|
||||
logger.debug("exchange_info 写入 DB 失败: %s", e)
|
||||
break
|
||||
except (asyncio.TimeoutError, BinanceAPIException, OSError) as e:
|
||||
last_err = e
|
||||
|
|
|
|||
|
|
@ -231,6 +231,17 @@ DEFAULT_TRADING_CONFIG = {
|
|||
'MIN_VOLUME_24H_STRICT': 50000000, # 严格过滤≥5000万美元
|
||||
'MIN_VOLATILITY': 0.03, # 最小波动率3%,过滤死币
|
||||
'MIN_SIGNAL_STRENGTH': 8, # 信号强度≥8(2026-01-29优化:从7提高到8,减少低质量信号,提升胜率)
|
||||
# ===== 资金费率过滤(开仓前)=====
|
||||
'FUNDING_RATE_FILTER_ENABLED': True, # 开仓前检查资金费率,避免在费率极端不利于己方时进场
|
||||
'MAX_FUNDING_RATE_FOR_LONG': 0.001, # 做多时 lastFundingRate 超过此值则跳过(0.1%=多头付费高)
|
||||
'MIN_FUNDING_RATE_FOR_SHORT': -0.001, # 做空时 lastFundingRate 低于此值则跳过(-0.1%=空头付费高)
|
||||
# 扫描阶段资金费率过滤:排除 |lastFundingRate| 过大的标的,避免进入 TOP_N
|
||||
'SCAN_FUNDING_RATE_FILTER_ENABLED': True,
|
||||
'SCAN_FUNDING_RATE_MAX_ABS': 0.001, # 绝对值超过 0.1% 则从扫描候选剔除
|
||||
# 主动买卖量过滤(可选):与方向一致时通过,极端反向时跳过
|
||||
'TAKER_RATIO_FILTER_ENABLED': False, # 默认关闭,开启后做多要求 buySellRatio≥下限、做空要求≤上限
|
||||
'MIN_TAKER_BUY_RATIO_FOR_LONG': 0.85, # 做多时最近1h buySellRatio 低于此值则跳过(主动买不足)
|
||||
'MAX_TAKER_BUY_RATIO_FOR_SHORT': 1.15, # 做空时最近1h buySellRatio 高于此值则跳过(主动卖不足)
|
||||
|
||||
# ===== 动态过滤优化 =====
|
||||
'BETA_FILTER_ENABLED': True, # 大盘共振过滤:BTC/ETH下跌时屏蔽多单
|
||||
|
|
|
|||
|
|
@ -119,7 +119,35 @@ class MarketScanner:
|
|||
pre_filtered_symbols.append(symbol)
|
||||
|
||||
logger.info(f"初步筛选后,需要详细分析的交易对: {len(pre_filtered_symbols)} 个")
|
||||
|
||||
|
||||
# 扫描阶段资金费率过滤:排除 |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))
|
||||
if scan_funding_enabled and pre_filtered_symbols:
|
||||
try:
|
||||
premium_all = await self.client.get_premium_index(None) # 全量,一次请求
|
||||
rate_map = {}
|
||||
if isinstance(premium_all, list):
|
||||
for item in premium_all:
|
||||
if isinstance(item, dict) and 'symbol' in item:
|
||||
try:
|
||||
rate_map[item['symbol']] = float(item.get('lastFundingRate', 0))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
elif isinstance(premium_all, dict) and premium_all.get('symbol'):
|
||||
rate_map[premium_all['symbol']] = float(premium_all.get('lastFundingRate', 0))
|
||||
if rate_map:
|
||||
before = len(pre_filtered_symbols)
|
||||
pre_filtered_symbols = [
|
||||
s for s in pre_filtered_symbols
|
||||
if abs(rate_map.get(s, 0)) <= scan_funding_max_abs
|
||||
]
|
||||
excluded = before - len(pre_filtered_symbols)
|
||||
if excluded > 0:
|
||||
logger.info(f"扫描阶段资金费率过滤: 排除 {excluded} 个标的 (|lastFundingRate| > {scan_funding_max_abs}),剩余 {len(pre_filtered_symbols)} 个")
|
||||
except Exception as e:
|
||||
logger.debug("扫描阶段资金费率过滤失败,继续使用原列表: %s", e)
|
||||
|
||||
# 只对符合条件的交易对进行详细分析(获取K线和技术指标)
|
||||
# ⚠️ 并发数说明:
|
||||
# - 这是单个账户扫描时,同时分析多少个交易对(不是用户进程数)
|
||||
|
|
|
|||
|
|
@ -178,6 +178,14 @@ class TradingStrategy:
|
|||
|
||||
# 确定交易方向(基于技术指标)
|
||||
trade_direction = trade_signal['direction']
|
||||
# 开仓前资金费率过滤:避免在费率极端不利于己方时进场
|
||||
if not await self._check_funding_rate_filter(symbol, trade_direction):
|
||||
logger.info(f"{symbol} 资金费率过滤未通过,跳过开仓")
|
||||
continue
|
||||
# 开仓前主动买卖量过滤(可选):与方向一致时通过
|
||||
if not await self._check_taker_ratio_filter(symbol, trade_direction):
|
||||
logger.info(f"{symbol} 主动买卖量过滤未通过,跳过开仓")
|
||||
continue
|
||||
entry_reason = trade_signal['reason']
|
||||
|
||||
signal_strength = trade_signal.get('strength', 0)
|
||||
|
|
@ -353,6 +361,65 @@ class TradingStrategy:
|
|||
await asyncio.sleep(check_interval)
|
||||
waited += check_interval
|
||||
|
||||
async def _check_funding_rate_filter(self, symbol: str, direction: str) -> bool:
|
||||
"""
|
||||
开仓前资金费率过滤:避免在费率极端不利于己方时进场(做多时费率过高、做空时费率过负则跳过)。
|
||||
依赖 REST get_premium_index(symbol) 的 lastFundingRate。
|
||||
"""
|
||||
enabled = bool(config.TRADING_CONFIG.get('FUNDING_RATE_FILTER_ENABLED', True))
|
||||
if not enabled:
|
||||
return True
|
||||
try:
|
||||
data = await self.client.get_premium_index(symbol)
|
||||
if not data or not isinstance(data, dict):
|
||||
return True
|
||||
rate_raw = data.get('lastFundingRate')
|
||||
if rate_raw is None:
|
||||
return True
|
||||
rate = float(rate_raw)
|
||||
max_long = float(config.TRADING_CONFIG.get('MAX_FUNDING_RATE_FOR_LONG', 0.001))
|
||||
min_short = float(config.TRADING_CONFIG.get('MIN_FUNDING_RATE_FOR_SHORT', -0.001))
|
||||
if direction == 'BUY' and rate > max_long:
|
||||
logger.info(f"{symbol} 资金费率过滤:做多跳过(lastFundingRate={rate:.6f} > {max_long})")
|
||||
return False
|
||||
if direction == 'SELL' and rate < min_short:
|
||||
logger.info(f"{symbol} 资金费率过滤:做空跳过(lastFundingRate={rate:.6f} < {min_short})")
|
||||
return False
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.debug(f"{symbol} 资金费率检查失败(放行): {e}")
|
||||
return True
|
||||
|
||||
async def _check_taker_ratio_filter(self, symbol: str, direction: str) -> bool:
|
||||
"""
|
||||
开仓前主动买卖量过滤(可选):做多要求近期主动买占比不低于下限,做空要求主动卖占比不低于下限。
|
||||
依赖 get_taker_long_short_ratio(symbol, period='1h', limit=1),取最近一条的 buySellRatio。
|
||||
"""
|
||||
enabled = bool(config.TRADING_CONFIG.get('TAKER_RATIO_FILTER_ENABLED', False))
|
||||
if not enabled:
|
||||
return True
|
||||
try:
|
||||
arr = await self.client.get_taker_long_short_ratio(symbol, period='1h', limit=3)
|
||||
if not arr or not isinstance(arr, list):
|
||||
return True
|
||||
latest = arr[0] if arr else {}
|
||||
ratio_raw = latest.get('buySellRatio')
|
||||
if ratio_raw is None:
|
||||
return True
|
||||
ratio = float(ratio_raw)
|
||||
min_long = float(config.TRADING_CONFIG.get('MIN_TAKER_BUY_RATIO_FOR_LONG', 0.85))
|
||||
max_short = float(config.TRADING_CONFIG.get('MAX_TAKER_BUY_RATIO_FOR_SHORT', 1.15))
|
||||
if direction == 'BUY' and ratio < min_long:
|
||||
logger.info(f"{symbol} 主动买卖量过滤:做多跳过(buySellRatio={ratio:.3f} < {min_long})")
|
||||
return False
|
||||
if direction == 'SELL' and ratio > max_short:
|
||||
logger.info(f"{symbol} 主动买卖量过滤:做空跳过(buySellRatio={ratio:.3f} > {max_short})")
|
||||
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:
|
||||
"""
|
||||
成交量确认 - 确保有足够的成交量支撑
|
||||
|
|
|
|||
870
持仓记录_2026-02-16T09-45-37.json
Normal file
870
持仓记录_2026-02-16T09-45-37.json
Normal file
|
|
@ -0,0 +1,870 @@
|
|||
[
|
||||
{
|
||||
"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