mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-11 09:18:08 +00:00
114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
import type { AsterDepth, AsterTicker } from "../exchanges/types";
|
||
|
||
export function getTopPrices(depth?: AsterDepth | null): { topBid: number | null; topAsk: number | null } {
|
||
const bid = Number(depth?.bids?.[0]?.[0]);
|
||
const ask = Number(depth?.asks?.[0]?.[0]);
|
||
return {
|
||
topBid: Number.isFinite(bid) ? bid : null,
|
||
topAsk: Number.isFinite(ask) ? ask : null,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 获取指定档位的盘口价格
|
||
* @param depth 深度数据
|
||
* @param level 档位(1=买1/卖1,2=买2/卖2,以此类推)
|
||
* @returns 指定档位的买卖价格,如果该档位不存在则回退到最近的有效档位
|
||
*/
|
||
export function getPricesAtLevel(
|
||
depth?: AsterDepth | null,
|
||
level: number = 1
|
||
): { bidAtLevel: number | null; askAtLevel: number | null } {
|
||
const index = Math.max(0, level - 1);
|
||
|
||
// 尝试获取指定档位,如果不存在则回退到最近的有效档位
|
||
const bids = depth?.bids ?? [];
|
||
const asks = depth?.asks ?? [];
|
||
|
||
let bidAtLevel: number | null = null;
|
||
let askAtLevel: number | null = null;
|
||
|
||
// 从指定档位向前查找第一个有效的买价
|
||
for (let i = Math.min(index, bids.length - 1); i >= 0; i--) {
|
||
const bid = Number(bids[i]?.[0]);
|
||
if (Number.isFinite(bid)) {
|
||
bidAtLevel = bid;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 从指定档位向前查找第一个有效的卖价
|
||
for (let i = Math.min(index, asks.length - 1); i >= 0; i--) {
|
||
const ask = Number(asks[i]?.[0]);
|
||
if (Number.isFinite(ask)) {
|
||
askAtLevel = ask;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return { bidAtLevel, askAtLevel };
|
||
}
|
||
|
||
export function getMidOrLast(depth?: AsterDepth | null, ticker?: AsterTicker | null): number | null {
|
||
const { topBid, topAsk } = getTopPrices(depth);
|
||
if (topBid != null && topAsk != null) return (topBid + topAsk) / 2;
|
||
const last = Number(ticker?.lastPrice);
|
||
return Number.isFinite(last) ? last : null;
|
||
}
|
||
|
||
/**
|
||
* 计算从盘口一档到目标价格之间的挂单总量
|
||
* @param depth 深度数据
|
||
* @param side 挂单方向: BUY 检查 bids, SELL 检查 asks
|
||
* @param targetPrice 目标挂单价格
|
||
* @returns 从一档到目标价格之间的挂单总量 (不包含目标价格本身)
|
||
*/
|
||
export function getDepthBetweenPrices(
|
||
depth: AsterDepth | null | undefined,
|
||
side: "BUY" | "SELL",
|
||
targetPrice: number
|
||
): number {
|
||
if (!depth) return 0;
|
||
if (!Number.isFinite(targetPrice) || targetPrice <= 0) return 0;
|
||
|
||
let total = 0;
|
||
|
||
if (side === "BUY") {
|
||
// BUY 订单挂在 bid 侧,检查从 bid1 到目标价格之间的所有 bids
|
||
// bids 按价格从高到低排序,目标价格 < bid1
|
||
const bids = depth.bids ?? [];
|
||
for (const level of bids) {
|
||
const price = Number(level[0]);
|
||
const qty = Number(level[1]);
|
||
if (!Number.isFinite(price) || !Number.isFinite(qty)) continue;
|
||
// 只计算价格 > 目标价格的档位 (目标价格以上的挂单)
|
||
if (price > targetPrice) {
|
||
total += qty;
|
||
} else {
|
||
// bids 是从高到低排序,一旦 price <= targetPrice 就停止
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
// SELL 订单挂在 ask 侧,检查从 ask1 到目标价格之间的所有 asks
|
||
// asks 按价格从低到高排序,目标价格 > ask1
|
||
const asks = depth.asks ?? [];
|
||
for (const level of asks) {
|
||
const price = Number(level[0]);
|
||
const qty = Number(level[1]);
|
||
if (!Number.isFinite(price) || !Number.isFinite(qty)) continue;
|
||
// 只计算价格 < 目标价格的档位 (目标价格以下的挂单)
|
||
if (price < targetPrice) {
|
||
total += qty;
|
||
} else {
|
||
// asks 是从低到高排序,一旦 price >= targetPrice 就停止
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return total;
|
||
}
|
||
|
||
|