From e4c5d36a2da3fabd0f233df15a563d520d08b287 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Wed, 24 Jun 2026 16:10:34 +0800
Subject: [PATCH] refactor(okx): 删除K线处理器并重命名止盈单方法为止损单
---
src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java | 125 ++++++++++++++++++++++++++---------------
1 files changed, 79 insertions(+), 46 deletions(-)
diff --git a/src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java b/src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java
index 2eb5ed0..a7ee107 100644
--- a/src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java
+++ b/src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java
@@ -208,17 +208,12 @@
});
}
- // ==================== 止盈条件单 ====================
+ // ==================== 止盈/止损条件单 ====================
/**
- * 异步创建止盈条件单(OKX 算法订单 — conditional 类型)。
+ * 异步创建止盈条件单(OKX 算法订单 — conditional 类型,tpTriggerPx)。
*
- * <p>服务器监控价格,达到触发价后自动以市价平仓。
- * 使用 OKX 的 {@code order-algo} 接口,ordType=conditional。
- *
- * <h3>止盈失败兜底</h3>
- * 止盈单创建失败时立即调用 {@link #marketClose(String, String)} 市价平仓,
- * 确保仓位不会因止损条件未挂上而无保护。
+ * <p>止盈单创建失败时立即调用 {@link #marketClose(String, String)} 市价平仓兜底。
*
* @param triggerPrice 触发价格
* @param orderType 平仓类型:"close_long" 平多 / "close_short" 平空
@@ -229,6 +224,34 @@
String orderType,
String size,
Consumer<String> onSuccess) {
+ placeConditionalClose(triggerPrice, orderType, size, onSuccess, false);
+ }
+
+ /**
+ * 异步创建止损条件单(OKX 算法订单 — conditional 类型,slTriggerPx)。
+ *
+ * <p>止损单创建失败时立即调用 {@link #marketClose(String, String)} 市价平仓兜底。
+ *
+ * @param triggerPrice 触发价格
+ * @param orderType 平仓类型:"close_long" 平多 / "close_short" 平空
+ * @param size 平仓张数(正数,如 "15")
+ * @param onSuccess 成功回调,接收 algoId(可为 null)
+ */
+ public void placeStopLoss(BigDecimal triggerPrice,
+ String orderType,
+ String size,
+ Consumer<String> onSuccess) {
+ placeConditionalClose(triggerPrice, orderType, size, onSuccess, true);
+ }
+
+ /**
+ * 通用平仓条件单:isStopLoss=true 用 slTriggerPx/slOrdPx,false 用 tpTriggerPx/tpOrdPx。
+ */
+ private void placeConditionalClose(BigDecimal triggerPrice,
+ String orderType,
+ String size,
+ Consumer<String> onSuccess,
+ boolean isStopLoss) {
executor.execute(() -> {
String posSide = null;
try {
@@ -240,11 +263,11 @@
side = "buy";
posSide = "short";
} else {
- log.error("[TradeExec-OKX] 未知止盈类型: {}", orderType);
+ log.error("[TradeExec-OKX] 未知平仓类型: {}", orderType);
return;
}
- // OKX conditional 止盈止损使用 tpTriggerPx/tpOrdPx 或 slTriggerPx/slOrdPx
+ String label = isStopLoss ? "止损" : "止盈";
JSONObject body = new JSONObject();
body.put("instId", contract);
body.put("tdMode", "cross");
@@ -252,29 +275,35 @@
body.put("posSide", posSide);
body.put("ordType", "conditional");
body.put("sz", size);
- // "close_long"=平多(止盈), "close_short"=平空(止盈)
- body.put("tpTriggerPx", triggerPrice.stripTrailingZeros().toPlainString());
- body.put("tpTriggerPxType", "last");
- body.put("tpOrdPx", "-1");
+ // 止盈用 tp 系列字段,止损用 sl 系列字段
+ if (isStopLoss) {
+ body.put("slTriggerPx", triggerPrice.stripTrailingZeros().toPlainString());
+ body.put("slTriggerPxType", "last");
+ body.put("slOrdPx", "-1");
+ } else {
+ body.put("tpTriggerPx", triggerPrice.stripTrailingZeros().toPlainString());
+ body.put("tpTriggerPxType", "last");
+ body.put("tpOrdPx", "-1");
+ }
JSONObject resp = okPost("/api/v5/trade/order-algo", body.toJSONString());
String code = resp.getString("code");
if (!"0".equals(code)) {
- log.error("[TradeExec-OKX] 止盈单创建失败, code:{}, msg:{}, 立即市价止盈",
- code, resp.getString("msg"));
+ log.error("[TradeExec-OKX] {}单创建失败, code:{}, msg:{}, 立即市价{}",
+ label, code, resp.getString("msg"), label);
marketClose(size, posSide);
return;
}
JSONArray data = resp.getJSONArray("data");
String algoId = (data != null && !data.isEmpty())
? data.getJSONObject(0).getString("algoId") : null;
- log.info("[TradeExec-OKX] 止盈单已创建, triggerPx:{}, type:{}, sz:{}, algoId:{}",
- triggerPrice, orderType, size, algoId);
+ log.info("[TradeExec-OKX] {}单已创建, triggerPx:{}, type:{}, sz:{}, algoId:{}",
+ label, triggerPrice, orderType, size, algoId);
if (onSuccess != null) {
onSuccess.accept(algoId);
}
} catch (Exception e) {
- log.error("[TradeExec-OKX] 止盈单创建失败, triggerPx:{}, sz:{}, 立即市价止盈",
+ log.error("[TradeExec-OKX] 创建失败, triggerPx:{}, sz:{}, 立即市价{}",
triggerPrice, size, e);
if (posSide != null) {
marketClose(size, posSide);
@@ -448,39 +477,43 @@
public void cancelAllPriceTriggeredOrders() {
executor.execute(() -> {
try {
- // 1. 查询所有待处理的算法订单
- String queryPath = "/api/v5/trade/orders-algo-pending?instId=" + contract;
- JSONObject queryResp = okGet(queryPath);
- String code = queryResp.getString("code");
- if (!"0".equals(code)) {
- log.warn("[TradeExec-OKX] 查询待处理条件单失败, code:{}, msg:{}",
- code, queryResp.getString("msg"));
- return;
+ // ordType 是 orders-algo-pending 的必填参数,需分别查询 conditional 和 trigger
+ JSONArray cancelBody = new JSONArray();
+ for (String ordType : new String[]{"conditional", "trigger"}) {
+ String queryPath = "/api/v5/trade/orders-algo-pending?instId=" + contract
+ + "&ordType=" + ordType;
+ try {
+ JSONObject queryResp = okGet(queryPath);
+ if (!"0".equals(queryResp.getString("code"))) {
+ log.warn("[TradeExec-OKX] 查询 pending ordType={} 失败, code:{}, msg:{}",
+ ordType, queryResp.getString("code"), queryResp.getString("msg"));
+ continue;
+ }
+ JSONArray data = queryResp.getJSONArray("data");
+ if (data != null) {
+ for (int i = 0; i < data.size(); i++) {
+ JSONObject order = data.getJSONObject(i);
+ String algoId = order.getString("algoId");
+ if (algoId == null) {
+ continue;
+ }
+ JSONObject item = new JSONObject();
+ item.put("algoId", algoId);
+ item.put("instId", contract);
+ cancelBody.add(item);
+ }
+ }
+ } catch (Exception e) {
+ log.warn("[TradeExec-OKX] 查询待处理条件单失败, ordType:{}", ordType, e);
+ }
}
- JSONArray data = queryResp.getJSONArray("data");
- if (data == null || data.isEmpty()) {
+ if (cancelBody.isEmpty()) {
log.info("[TradeExec-OKX] 无待处理条件单");
return;
}
- // 2. 收集所有 algoId
- JSONArray cancelBody = new JSONArray();
- for (int i = 0; i < data.size(); i++) {
- JSONObject order = data.getJSONObject(i);
- String algoId = order.getString("algoId");
- if (algoId == null) continue;
- JSONObject item = new JSONObject();
- item.put("algoId", algoId);
- item.put("instId", contract);
- cancelBody.add(item);
- }
-
- if (cancelBody.isEmpty()) {
- return;
- }
-
- // 3. 批量取消
+ // 批量取消
JSONObject cancelResp = okPost("/api/v5/trade/cancel-algos", cancelBody.toJSONString());
String cancelCode = cancelResp.getString("code");
if (!"0".equals(cancelCode)) {
--
Gitblit v1.9.1