更新交易引擎,添加最大平仓滑点百分比配置以优化价格操控保护逻辑,确保在市价平仓时价格与标记价格的偏差在允许范围内。

This commit is contained in:
discountry
2025-09-24 03:49:37 +08:00
parent 9c45458507
commit dc6f9ee72e
6 changed files with 161 additions and 16 deletions
+28 -2
View File
@@ -4,15 +4,16 @@ export interface PositionSnapshot {
positionAmt: number;
entryPrice: number;
unrealizedProfit: number;
markPrice: number | null;
}
export function getPosition(snapshot: AsterAccountSnapshot | null, symbol: string): PositionSnapshot {
if (!snapshot) {
return { positionAmt: 0, entryPrice: 0, unrealizedProfit: 0 };
return { positionAmt: 0, entryPrice: 0, unrealizedProfit: 0, markPrice: null };
}
const positions = snapshot.positions?.filter((p) => p.symbol === symbol) ?? [];
if (positions.length === 0) {
return { positionAmt: 0, entryPrice: 0, unrealizedProfit: 0 };
return { positionAmt: 0, entryPrice: 0, unrealizedProfit: 0, markPrice: null };
}
const NON_ZERO_EPS = 1e-8;
const withExposure = positions.filter((p) => Math.abs(Number(p.positionAmt)) > NON_ZERO_EPS);
@@ -20,10 +21,13 @@ export function getPosition(snapshot: AsterAccountSnapshot | null, symbol: strin
withExposure.find((p) => p.positionSide === "BOTH") ??
withExposure.sort((a, b) => Math.abs(Number(b.positionAmt)) - Math.abs(Number(a.positionAmt)))[0] ??
positions[0];
const rawMark = Number(selected?.markPrice);
const markPrice = Number.isFinite(rawMark) && rawMark > 0 ? rawMark : null;
return {
positionAmt: Number(selected?.positionAmt) || 0,
entryPrice: Number(selected?.entryPrice) || 0,
unrealizedProfit: Number(selected?.unrealizedProfit) || 0,
markPrice,
};
}
@@ -47,3 +51,25 @@ export function calcTrailingActivationPrice(entryPrice: number, qty: number, sid
}
return entryPrice - profit / Math.abs(qty);
}
/**
* Return true if the intended order price is within the allowed deviation from mark price.
* - For BUY: orderPrice must be <= markPrice * (1 + maxPct)
* - For SELL: orderPrice must be >= markPrice * (1 - maxPct)
* If markPrice is null/invalid, the check passes (no protection possible).
*/
export function isOrderPriceAllowedByMark(params: {
side: "BUY" | "SELL";
orderPrice: number | null | undefined;
markPrice: number | null | undefined;
maxPct: number;
}): boolean {
const { side, orderPrice, markPrice, maxPct } = params;
const price = Number(orderPrice);
const mark = Number(markPrice);
if (!Number.isFinite(price) || !Number.isFinite(mark) || mark <= 0) return true;
if (side === "BUY") {
return price <= mark * (1 + Math.max(0, maxPct));
}
return price >= mark * (1 - Math.max(0, maxPct));
}