mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-10 08:48:07 +00:00
add trend skip
This commit is contained in:
@@ -58,6 +58,8 @@ export class OffsetMakerEngine {
|
|||||||
private accountSnapshot: AsterAccountSnapshot | null = null;
|
private accountSnapshot: AsterAccountSnapshot | null = null;
|
||||||
private depthSnapshot: AsterDepth | null = null;
|
private depthSnapshot: AsterDepth | null = null;
|
||||||
private tickerSnapshot: AsterTicker | null = null;
|
private tickerSnapshot: AsterTicker | null = null;
|
||||||
|
private lastKline: AsterKline | null = null;
|
||||||
|
private liveCandle: { startMs: number; open: number; close: number } | null = null;
|
||||||
private openOrders: AsterOrder[] = [];
|
private openOrders: AsterOrder[] = [];
|
||||||
|
|
||||||
private readonly locks: OrderLockMap = {};
|
private readonly locks: OrderLockMap = {};
|
||||||
@@ -80,6 +82,8 @@ export class OffsetMakerEngine {
|
|||||||
private quoteAssetId: number | null = null;
|
private quoteAssetId: number | null = null;
|
||||||
private spotEntryPrice: number | null = null;
|
private spotEntryPrice: number | null = null;
|
||||||
private lastSpotWallet = 0;
|
private lastSpotWallet = 0;
|
||||||
|
private spotKlineUp: boolean | null = null;
|
||||||
|
private lastSpotBuyGuardLogged = false;
|
||||||
|
|
||||||
private timer: ReturnType<typeof setInterval> | null = null;
|
private timer: ReturnType<typeof setInterval> | null = null;
|
||||||
private processing = false;
|
private processing = false;
|
||||||
@@ -255,8 +259,15 @@ export class OffsetMakerEngine {
|
|||||||
|
|
||||||
safeSubscribe<AsterKline[]>(
|
safeSubscribe<AsterKline[]>(
|
||||||
this.exchange.watchKlines.bind(this.exchange, this.config.symbol, "1m"),
|
this.exchange.watchKlines.bind(this.exchange, this.config.symbol, "1m"),
|
||||||
(_klines) => {
|
(klines) => {
|
||||||
/* no-op */
|
if (!Array.isArray(klines) || !klines.length) return;
|
||||||
|
const latest = klines[klines.length - 1];
|
||||||
|
this.lastKline = latest;
|
||||||
|
const open = Number(latest.open);
|
||||||
|
const close = Number(latest.close);
|
||||||
|
if (Number.isFinite(open) && Number.isFinite(close)) {
|
||||||
|
this.spotKlineUp = close > open;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
log,
|
log,
|
||||||
{
|
{
|
||||||
@@ -323,6 +334,7 @@ export class OffsetMakerEngine {
|
|||||||
const isSpotMarket = this.marketType === "spot";
|
const isSpotMarket = this.marketType === "spot";
|
||||||
const spotBalances = isSpotMarket ? this.getSpotBalances() : null;
|
const spotBalances = isSpotMarket ? this.getSpotBalances() : null;
|
||||||
const balancesForSpot = isSpotMarket ? spotBalances ?? { baseAvailable: 0, quoteAvailable: 0 } : spotBalances;
|
const balancesForSpot = isSpotMarket ? spotBalances ?? { baseAvailable: 0, quoteAvailable: 0 } : spotBalances;
|
||||||
|
this.updateLiveCandle();
|
||||||
const handledImbalance = await this.handleImbalanceExit(position, buySum, sellSum);
|
const handledImbalance = await this.handleImbalanceExit(position, buySum, sellSum);
|
||||||
if (handledImbalance) {
|
if (handledImbalance) {
|
||||||
this.emitUpdate();
|
this.emitUpdate();
|
||||||
@@ -361,6 +373,7 @@ export class OffsetMakerEngine {
|
|||||||
}
|
}
|
||||||
const desired: DesiredOrder[] = [];
|
const desired: DesiredOrder[] = [];
|
||||||
const canEnter = !this.rateLimit.shouldBlockEntries();
|
const canEnter = !this.rateLimit.shouldBlockEntries();
|
||||||
|
const allowSpotBuy = !isSpotMarket || this.isSpotKlineUp();
|
||||||
|
|
||||||
if (absPosition < EPS && isSpotMarket) {
|
if (absPosition < EPS && isSpotMarket) {
|
||||||
this.entryPricePendingLogged = false;
|
this.entryPricePendingLogged = false;
|
||||||
@@ -375,22 +388,29 @@ export class OffsetMakerEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!skipBuySide && canEnter) {
|
if (!skipBuySide && canEnter) {
|
||||||
const buyAmount = this.computeSpotOrderSize({
|
if (!allowSpotBuy) {
|
||||||
side: "BUY",
|
if (this.lastBuyPriceViable) {
|
||||||
desiredAmount: this.config.tradeAmount,
|
this.tradeLog.push("info", "现货买入仅在1m阳线,当前跳过买单");
|
||||||
price: bidPrice != null ? Number(bidPrice) : null,
|
this.lastBuyPriceViable = false;
|
||||||
balances: balancesForSpot,
|
}
|
||||||
});
|
} else {
|
||||||
if (bidPrice != null && buyAmount >= EPS) {
|
const buyAmount = this.computeSpotOrderSize({
|
||||||
this.lastBuyPriceViable = true;
|
side: "BUY",
|
||||||
desired.push({ side: "BUY", price: bidPrice, amount: buyAmount, reduceOnly: false });
|
desiredAmount: this.config.tradeAmount,
|
||||||
} else if (this.lastBuyPriceViable) {
|
price: bidPrice != null ? Number(bidPrice) : null,
|
||||||
this.lastBuyPriceViable = false;
|
balances: balancesForSpot,
|
||||||
const reason =
|
});
|
||||||
buyAmount < EPS && isSpotMarket
|
if (bidPrice != null && buyAmount >= EPS) {
|
||||||
? "现货可用报价资产不足,跳过买单"
|
this.lastBuyPriceViable = true;
|
||||||
: "跳过买单:价差不足以构造maker价格";
|
desired.push({ side: "BUY", price: bidPrice, amount: buyAmount, reduceOnly: false });
|
||||||
this.tradeLog.push("info", reason);
|
} else if (this.lastBuyPriceViable) {
|
||||||
|
this.lastBuyPriceViable = false;
|
||||||
|
const reason =
|
||||||
|
buyAmount < EPS && isSpotMarket
|
||||||
|
? "现货可用报价资产不足,跳过买单"
|
||||||
|
: "跳过买单:价差不足以构造maker价格";
|
||||||
|
this.tradeLog.push("info", reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!skipSellSide && canEnter) {
|
if (!skipSellSide && canEnter) {
|
||||||
@@ -428,7 +448,14 @@ export class OffsetMakerEngine {
|
|||||||
} else if (absPosition < EPS) {
|
} else if (absPosition < EPS) {
|
||||||
this.entryPricePendingLogged = false;
|
this.entryPricePendingLogged = false;
|
||||||
if (!skipBuySide && canEnter) {
|
if (!skipBuySide && canEnter) {
|
||||||
desired.push({ side: "BUY", price: bidPrice, amount: this.config.tradeAmount, reduceOnly: false });
|
if (isSpotMarket && !allowSpotBuy) {
|
||||||
|
if (this.lastBuyPriceViable) {
|
||||||
|
this.tradeLog.push("info", "现货买入仅在1m阳线,当前跳过买单");
|
||||||
|
this.lastBuyPriceViable = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
desired.push({ side: "BUY", price: bidPrice, amount: this.config.tradeAmount, reduceOnly: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!skipSellSide && canEnter) {
|
if (!skipSellSide && canEnter) {
|
||||||
if (isSpotMarket && minSell > 0 && this.minBaseAmount != null) {
|
if (isSpotMarket && minSell > 0 && this.minBaseAmount != null) {
|
||||||
@@ -955,6 +982,28 @@ export class OffsetMakerEngine {
|
|||||||
return getMidOrLast(this.depthSnapshot, this.tickerSnapshot);
|
return getMidOrLast(this.depthSnapshot, this.tickerSnapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isSpotKlineUp(): boolean {
|
||||||
|
return this.spotKlineUp === true || this.isLiveCandleUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
private isLiveCandleUp(): boolean {
|
||||||
|
if (!this.liveCandle) return false;
|
||||||
|
return this.liveCandle.close > this.liveCandle.open;
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateLiveCandle(): void {
|
||||||
|
const price = this.getReferencePrice();
|
||||||
|
if (!Number.isFinite(price)) return;
|
||||||
|
const now = Date.now();
|
||||||
|
const minuteStart = now - (now % 60000);
|
||||||
|
if (!this.liveCandle || this.liveCandle.startMs !== minuteStart) {
|
||||||
|
this.liveCandle = { startMs: minuteStart, open: price as number, close: price as number };
|
||||||
|
} else {
|
||||||
|
this.liveCandle.close = price as number;
|
||||||
|
}
|
||||||
|
this.spotKlineUp = this.isLiveCandleUp();
|
||||||
|
}
|
||||||
|
|
||||||
private getPositionSnapshot(): PositionSnapshot {
|
private getPositionSnapshot(): PositionSnapshot {
|
||||||
const position = getPosition(this.accountSnapshot, this.config.symbol);
|
const position = getPosition(this.accountSnapshot, this.config.symbol);
|
||||||
if (this.marketType === "spot" && this.spotEntryPrice != null && Math.abs(position.positionAmt) > EPS) {
|
if (this.marketType === "spot" && this.spotEntryPrice != null && Math.abs(position.positionAmt) > EPS) {
|
||||||
|
|||||||
Reference in New Issue
Block a user