mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-11 09:18:08 +00:00
feat: 添加止损单去抖机制,避免重复提交同价同向止损单
This commit is contained in:
@@ -111,6 +111,12 @@ export class TrendEngine {
|
|||||||
private ordersSnapshotReady = false;
|
private ordersSnapshotReady = false;
|
||||||
private startupLogged = false;
|
private startupLogged = false;
|
||||||
private entryPricePendingLogged = false;
|
private entryPricePendingLogged = false;
|
||||||
|
// 记录最近一次止损下单尝试,用于抑制在无订单流识别时的重复挂单
|
||||||
|
private lastStopAttempt: { side: "BUY" | "SELL" | null; price: number | null; at: number } = {
|
||||||
|
side: null,
|
||||||
|
price: null,
|
||||||
|
at: 0,
|
||||||
|
};
|
||||||
private readonly copyrightFingerprint = crypto
|
private readonly copyrightFingerprint = crypto
|
||||||
.createHash("sha256")
|
.createHash("sha256")
|
||||||
.update(decryptCopyright())
|
.update(decryptCopyright())
|
||||||
@@ -522,9 +528,12 @@ export class TrendEngine {
|
|||||||
this.config.trailingProfit
|
this.config.trailingProfit
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentStop = this.openOrders.find(
|
// 对于部分交易所(如 Lighter),触发类订单在订单流中可能显示为 LIMIT,但会带有 stopPrice。
|
||||||
(o) => o.type === "STOP_MARKET" && o.side === stopSide
|
// 因此将带有有效 stopPrice 的同向订单也视为当前止损单。
|
||||||
);
|
const currentStop = this.openOrders.find((o) => {
|
||||||
|
const hasStopPrice = Number.isFinite(Number(o.stopPrice)) && Number(o.stopPrice) > 0;
|
||||||
|
return o.side === stopSide && (o.type === "STOP_MARKET" || hasStopPrice);
|
||||||
|
});
|
||||||
const currentTrailing = this.openOrders.find(
|
const currentTrailing = this.openOrders.find(
|
||||||
(o) => o.type === "TRAILING_STOP_MARKET" && o.side === stopSide
|
(o) => o.type === "TRAILING_STOP_MARKET" && o.side === stopSide
|
||||||
);
|
);
|
||||||
@@ -639,7 +648,16 @@ export class TrendEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!currentStop) {
|
if (!currentStop) {
|
||||||
await this.tryPlaceStopLoss(stopSide, Number(formatPriceToString(stopPrice, Math.max(0, Math.floor(Math.log10(1 / this.config.priceTick))))), price);
|
await this.tryPlaceStopLoss(
|
||||||
|
stopSide,
|
||||||
|
Number(
|
||||||
|
formatPriceToString(
|
||||||
|
stopPrice,
|
||||||
|
Math.max(0, Math.floor(Math.log10(1 / this.config.priceTick)))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
price
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentTrailing && this.exchange.supportsTrailingStops()) {
|
if (!currentTrailing && this.exchange.supportsTrailingStops()) {
|
||||||
@@ -740,6 +758,18 @@ export class TrendEngine {
|
|||||||
stopPrice: number,
|
stopPrice: number,
|
||||||
lastPrice: number
|
lastPrice: number
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
// 短期去抖:在订单流无法正确识别止损单时,避免在极短时间内重复提交同价同向止损
|
||||||
|
const tick = Math.max(1e-9, this.config.priceTick);
|
||||||
|
const now = Date.now();
|
||||||
|
if (
|
||||||
|
this.lastStopAttempt.side === side &&
|
||||||
|
this.lastStopAttempt.price != null &&
|
||||||
|
Math.abs(stopPrice - Number(this.lastStopAttempt.price)) < tick &&
|
||||||
|
now - this.lastStopAttempt.at < 5000
|
||||||
|
) {
|
||||||
|
// 5 秒内同向同价重复尝试,直接跳过
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const position = getPosition(this.accountSnapshot, this.config.symbol);
|
const position = getPosition(this.accountSnapshot, this.config.symbol);
|
||||||
const quantity = Math.abs(position.positionAmt) || this.config.tradeAmount;
|
const quantity = Math.abs(position.positionAmt) || this.config.tradeAmount;
|
||||||
@@ -761,8 +791,11 @@ export class TrendEngine {
|
|||||||
},
|
},
|
||||||
{ priceTick: this.config.priceTick, qtyStep: this.config.qtyStep }
|
{ priceTick: this.config.priceTick, qtyStep: this.config.qtyStep }
|
||||||
);
|
);
|
||||||
|
this.lastStopAttempt = { side, price: stopPrice, at: Date.now() };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.tradeLog.push("error", `挂止损单失败: ${String(err)}`);
|
this.tradeLog.push("error", `挂止损单失败: ${String(err)}`);
|
||||||
|
// 记录尝试以避免在错误被抛回时立即再次重复尝试
|
||||||
|
this.lastStopAttempt = { side, price: stopPrice, at: Date.now() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user