From 782bebb2e734e1782e875fc2f45cbef71cb07712 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Fri, 05 Jun 2026 11:56:13 +0800
Subject: [PATCH] fix(okxNewPrice): 解决网格交易价格精度计算问题
---
src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java | 53 ++++++++++++++++++++++++++++++++++-------------------
1 files changed, 34 insertions(+), 19 deletions(-)
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
index 7b700d8..b8a94ce 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
@@ -356,7 +356,7 @@
// ---- 订单/条件单推送回调 ----
public void onOrderUpdate(String algoId, String state, String ordType) {
- if (!"effective".equals(state) && !"canceled".equals(state)) {
+ if (!"filled".equals(state) && !"canceled".equals(state)) {
return;
}
@@ -408,31 +408,33 @@
baseGridElement.setShortOrderId(baseShortTp.getEntryOrderId());
baseGridElement.setHasShortOrder(true);
- // 挂多仓止损 (id=-2 到 -11)
+ // 挂多仓止损 (id=-2 到 -11),每格 quantity 张
for (int id = -2; id >= -11; id--) {
OkxGridElement elem = OkxGridElement.findById(id);
if (elem == null) continue;
BigDecimal triggerPrice = elem.getGridPrice();
int finalId = id;
- executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", "1",
+ executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", config.getQuantity(),
profitId -> {
elem.setLongStopLossOrderId(profitId);
OkxGridElement.refreshIndices();
- log.info("[OKX] 多仓止损已挂, gridId:{}, 触发价:{}, stopLossId:{}", finalId, triggerPrice, profitId);
+ log.info("[OKX] 多仓止损已挂, gridId:{}, 触发价:{}, qty:{}, stopLossId:{}",
+ finalId, triggerPrice, config.getQuantity(), profitId);
});
}
- // 挂空仓止损 (id=2 到 11)
+ // 挂空仓止损 (id=2 到 11),每格 quantity 张
for (int id = 2; id <= 11; id++) {
OkxGridElement elem = OkxGridElement.findById(id);
if (elem == null) continue;
BigDecimal triggerPrice = elem.getGridPrice();
int finalId = id;
- executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", "1",
+ executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", config.getQuantity(),
profitId -> {
elem.setShortStopLossOrderId(profitId);
OkxGridElement.refreshIndices();
- log.info("[OKX] 空仓止损已挂, gridId:{}, 触发价:{}, stopLossId:{}", finalId, triggerPrice, profitId);
+ log.info("[OKX] 空仓止损已挂, gridId:{}, 触发价:{}, qty:{}, stopLossId:{}",
+ finalId, triggerPrice, config.getQuantity(), profitId);
});
}
@@ -561,10 +563,14 @@
BigDecimal triggerPrice = newEntryGrid.getGridPrice();
BigDecimal priceDiff = longEntryPrice.subtract(triggerPrice).abs();
- int entryQty = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
- entryQty = Math.max(1, entryQty);
+ // 精度补偿:步长被setScale截断,priceDiff/step可能产生1.99998→Down截断为1的问题
+ BigDecimal epsilon = new BigDecimal("0.00000001");
+ int count = priceDiff.add(epsilon).divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
+ count = Math.max(1, count);
+ int entryQty = count * Integer.parseInt(config.getQuantity());
String size = String.valueOf(entryQty);
- log.info("[OKX] 多仓止损触发 gridId:{}, 在gridId:{}挂{}张多单", gridId, newEntryGridId, entryQty);
+ log.info("[OKX] 多仓止损触发 gridId:{}, 在gridId:{}挂{}张多单(价差:{},步长:{},count:{},qty:{})",
+ gridId, newEntryGridId, entryQty, priceDiff, config.getStep(), count, config.getQuantity());
newEntryGrid.getLongTraderParam().setQuantity(size);
placeEntryOrderWithPreFlag(newEntryGrid, true, triggerPrice, size);
}
@@ -601,15 +607,22 @@
BigDecimal triggerPrice = newEntryGrid.getGridPrice();
BigDecimal priceDiff = shortEntryPrice.subtract(triggerPrice).abs();
- int entryQty = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
- entryQty = Math.max(1, entryQty);
+ // 精度补偿:步长被setScale截断,priceDiff/step可能产生1.99998→Down截断为1的问题
+ BigDecimal epsilon = new BigDecimal("0.00000001");
+ int count = priceDiff.add(epsilon).divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
+ count = Math.max(1, count);
+ int entryQty = count * Integer.parseInt(config.getQuantity());
String size = String.valueOf(entryQty);
- log.info("[OKX] 空仓止损触发 gridId:{}, 在gridId:{}挂{}张空单", gridId, newEntryGridId, entryQty);
+ log.info("[OKX] 空仓止损触发 gridId:{}, 在gridId:{}挂{}张空单(价差:{},步长:{},count:{},qty:{})",
+ gridId, newEntryGridId, entryQty, priceDiff, config.getStep(), count, config.getQuantity());
newEntryGrid.getShortTraderParam().setQuantity(size);
placeEntryOrderWithPreFlag(newEntryGrid, false, triggerPrice, size);
}
private void extendLongStopLoss(int filledQty) {
+ // filledQty 为本次新增止损张数 = count * quantity, 需要按 quantity 为粒度拆分为 count 个止损单
+ int qty = Integer.parseInt(config.getQuantity());
+ int stopLossCount = filledQty / qty;
int furthestSlId = 0;
for (OkxGridElement e : config.getGridElements()) {
if (e.getLongStopLossOrderId() != null && e.getId() < furthestSlId) {
@@ -617,14 +630,14 @@
}
}
if (furthestSlId == 0) furthestSlId = -11;
- log.info("[OKX] 多仓追挂止损, 当前最远止损gridId:{}, 追加{}张", furthestSlId, filledQty);
- for (int i = 0; i < filledQty; i++) {
+ log.info("[OKX] 多仓追挂止损, 当前最远止损gridId:{}, 追加{}单, 每单{}张", furthestSlId, stopLossCount, qty);
+ for (int i = 0; i < stopLossCount; i++) {
int newSlId = furthestSlId - i - 1;
OkxGridElement elem = OkxGridElement.findById(newSlId);
if (elem == null) continue;
BigDecimal triggerPrice = elem.getGridPrice();
int finalSlId = newSlId;
- executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", "1",
+ executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", config.getQuantity(),
profitId -> {
elem.setLongStopLossOrderId(profitId);
OkxGridElement.refreshIndices();
@@ -634,6 +647,8 @@
}
private void extendShortStopLoss(int filledQty) {
+ int qty = Integer.parseInt(config.getQuantity());
+ int stopLossCount = filledQty / qty;
int furthestSlId = 0;
for (OkxGridElement e : config.getGridElements()) {
if (e.getShortStopLossOrderId() != null && e.getId() > furthestSlId) {
@@ -641,14 +656,14 @@
}
}
if (furthestSlId == 0) furthestSlId = 11;
- log.info("[OKX] 空仓追挂止损, 当前最远止损gridId:{}, 追加{}张", furthestSlId, filledQty);
- for (int i = 0; i < filledQty; i++) {
+ log.info("[OKX] 空仓追挂止损, 当前最远止损gridId:{}, 追加{}单, 每单{}张", furthestSlId, stopLossCount, qty);
+ for (int i = 0; i < stopLossCount; i++) {
int newSlId = furthestSlId + i + 1;
OkxGridElement elem = OkxGridElement.findById(newSlId);
if (elem == null) continue;
BigDecimal triggerPrice = elem.getGridPrice();
int finalSlId = newSlId;
- executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", "1",
+ executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", config.getQuantity(),
profitId -> {
elem.setShortStopLossOrderId(profitId);
OkxGridElement.refreshIndices();
--
Gitblit v1.9.1