现价高于挂单价超过「间距 × 该倍数」时,撤单重挂

This commit is contained in:
tony 2026-07-08 23:47:17 +08:00
parent a448fe6a0a
commit 1e38b457f1

View File

@ -35,12 +35,17 @@ import java.util.concurrent.CopyOnWriteArrayList;
* <p>
* 网格间距 = atr_multiplier × ATR,并限制在 [min_gap, max_gap] 区间。
* 下方买单始终最多挂 1 笔:成交后再挂下一格,不会批量铺满网格。
* 若现价相对挂单价上行超过间距 × 1.5,撤单并按现价重新挂靠下一格,避免买单悬空。
* 采用限价挂单买入,市价止盈卖出。
* 网格间距变化时不撤销已有挂单,已成交仓位按最新间距计算止盈价。
*/
public class AutoGridStrategy extends BaseStrategy {
private static final String MARGIN_MODE = "crossed";
/**
* 现价高于挂单价超过「间距 × 该倍数」时,撤单重挂
*/
private static final BigDecimal BUY_REBASE_MULTIPLIER = new BigDecimal("1.5");
private final Logger logger = LoggerFactory.getLogger(AutoGridStrategy.class);
@ -303,6 +308,7 @@ public class AutoGridStrategy extends BaseStrategy {
checkPriceBounds();
refreshGridGap(false);
processTakeProfit();
rebaseStalePendingBuy();
replenishBuyGrids();
updateDashboard();
} catch (Exception e) {
@ -455,17 +461,79 @@ public class AutoGridStrategy extends BaseStrategy {
return;
}
BigDecimal nextBuyPrice = alignPriceDown(currentPrice, currentGridGap);
if (nextBuyPrice.compareTo(currentPrice) >= 0) {
nextBuyPrice = nextBuyPrice.subtract(currentGridGap);
}
if (nextBuyPrice.compareTo(lowerBound) >= 0 && !hasBuyOrderAt(nextBuyPrice)) {
BigDecimal nextBuyPrice = calcBuyPriceBelowCurrent();
if (nextBuyPrice != null
&& nextBuyPrice.compareTo(lowerBound) >= 0
&& !hasBuyOrderAt(nextBuyPrice)) {
placeLimitBuyOrder(nextBuyPrice);
}
}
}
/**
* 价格单边上行时,下方买单会悬空永远不成交。
* 当 现价 - 挂单价 > 间距 × 1.5 时,撤单并按现价重新对齐挂单(例:1532 / 间距 5 → 1530)。
*/
private void rebaseStalePendingBuy() {
if (!canPlaceBuyOrders() || currentPrice == null || currentGridGap == null
|| currentGridGap.compareTo(BigDecimal.ZERO) <= 0) {
return;
}
synchronized (tradeLock) {
if (pendingBuyOrders.isEmpty()) {
return;
}
GridBuyOrder pending = pendingBuyOrders.values().iterator().next();
BigDecimal distance = currentPrice.subtract(pending.buyPrice);
BigDecimal threshold = currentGridGap.multiply(BUY_REBASE_MULTIPLIER);
if (distance.compareTo(threshold) <= 0) {
return;
}
BigDecimal newPrice = calcBuyPriceBelowCurrent();
if (newPrice == null
|| newPrice.compareTo(lowerBound) < 0
|| newPrice.compareTo(pending.buyPrice) == 0) {
return;
}
try {
bitGetClient.cancelOrder(getSymbol(), pending.exchangeOrderId, pending.clientOrderId, null);
pendingBuyOrders.remove(priceKey(pending.buyPrice));
logger.info("买单距现价过远,撤单重挂:旧价={},现价={},间距={},阈值={},新价={}",
pending.buyPrice, currentPrice, currentGridGap, threshold, newPrice);
submitAlarm("买单追价重挂",
String.format("旧挂单价 %s,现价 %s,超过间距×1.5(%s),重挂至 %s",
formatPrice(pending.buyPrice), formatPrice(currentPrice),
formatPrice(threshold), formatPrice(newPrice)),
AlarmLevel.INFO);
placeLimitBuyOrder(newPrice);
} catch (Exception e) {
logger.error("买单追价重挂失败,旧价={}", pending.buyPrice, e);
submitAlarm("买单追价重挂失败",
String.format("旧价 %s:%s", formatPrice(pending.buyPrice), e.getMessage()),
AlarmLevel.ERROR);
}
}
}
/**
* 现价向下对齐到网格,确保严格低于现价。
*/
private BigDecimal calcBuyPriceBelowCurrent() {
if (currentPrice == null || currentGridGap == null
|| currentGridGap.compareTo(BigDecimal.ZERO) <= 0) {
return null;
}
BigDecimal nextBuyPrice = alignPriceDown(currentPrice, currentGridGap);
if (nextBuyPrice.compareTo(currentPrice) >= 0) {
nextBuyPrice = nextBuyPrice.subtract(currentGridGap);
}
return normalizePrice(nextBuyPrice);
}
/**
* 买单成交后,挂「成交价再下一格」的限价买单。
*/