mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-09 08:18:07 +00:00
Enhance entry price logic in Maker and Liquidity Maker strategies
- Added `entryDepthLevel` configuration option to `MakerConfig` and `LiquidityMakerConfig` for specifying order entry levels. - Implemented `getPricesAtLevel` utility function to retrieve bid and ask prices at specified depth levels. - Updated `MakerEngine`, `LiquidityMakerEngine`, and `OffsetMakerEngine` to utilize the new entry level logic for determining opening prices based on market depth. - Improved price handling to ensure more accurate order placements in varying market conditions.
This commit is contained in:
@@ -157,6 +157,8 @@ export interface MakerConfig {
|
||||
maxLogEntries: number;
|
||||
maxCloseSlippagePct: number;
|
||||
priceTick: number;
|
||||
/** 开仓挂单档位:1=买1/卖1,2=买2/卖2,以此类推。仅影响无仓位时的开仓挂单,平仓逻辑不受影响。默认1 */
|
||||
entryDepthLevel: number;
|
||||
}
|
||||
|
||||
export const makerConfig: MakerConfig = {
|
||||
@@ -172,6 +174,7 @@ export const makerConfig: MakerConfig = {
|
||||
0.05
|
||||
),
|
||||
priceTick: parseNumber(process.env.MAKER_PRICE_TICK ?? process.env.PRICE_TICK, 0.1),
|
||||
entryDepthLevel: Math.max(1, Math.floor(parseNumber(process.env.MAKER_ENTRY_DEPTH_LEVEL, 1))),
|
||||
};
|
||||
|
||||
export interface MakerPointsConfig {
|
||||
@@ -347,6 +350,8 @@ export interface LiquidityMakerConfig {
|
||||
closeTickOffset: number;
|
||||
/** 偏移判断阈值倍数,当一侧深度超出另一侧此倍数时取消薄端订单,默认2 */
|
||||
depthImbalanceRatio: number;
|
||||
/** 开仓挂单档位:1=买1/卖1,2=买2/卖2,以此类推。仅影响无仓位时的开仓挂单,平仓逻辑不受影响。默认1 */
|
||||
entryDepthLevel: number;
|
||||
}
|
||||
|
||||
export const liquidityMakerConfig: LiquidityMakerConfig = {
|
||||
@@ -364,6 +369,7 @@ export const liquidityMakerConfig: LiquidityMakerConfig = {
|
||||
priceTick: parseNumber(process.env.LIQUIDITY_MAKER_PRICE_TICK ?? process.env.MAKER_PRICE_TICK ?? process.env.PRICE_TICK, 0.1),
|
||||
closeTickOffset: Math.max(1, Math.floor(parseNumber(process.env.LIQUIDITY_MAKER_CLOSE_TICK_OFFSET, 1))),
|
||||
depthImbalanceRatio: Math.max(1.1, parseNumber(process.env.LIQUIDITY_MAKER_DEPTH_IMBALANCE_RATIO, 2)),
|
||||
entryDepthLevel: Math.max(1, Math.floor(parseNumber(process.env.MAKER_ENTRY_DEPTH_LEVEL, 1))),
|
||||
};
|
||||
|
||||
export function isBasisStrategyEnabled(): boolean {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { isOrderActiveStatus } from "../utils/order-status";
|
||||
import { getPosition, parseSymbolParts } from "../utils/strategy";
|
||||
import type { PositionSnapshot } from "../utils/strategy";
|
||||
import { computePositionPnl } from "../utils/pnl";
|
||||
import { getTopPrices, getMidOrLast } from "../utils/price";
|
||||
import { getTopPrices, getPricesAtLevel, getMidOrLast } from "../utils/price";
|
||||
import { shouldStopLoss } from "../utils/risk";
|
||||
import {
|
||||
marketClose,
|
||||
@@ -430,10 +430,18 @@ export class LiquidityMakerEngine {
|
||||
|
||||
// 直接使用orderbook价格,格式化为字符串避免精度问题
|
||||
const priceDecimals = this.getPriceDecimals();
|
||||
// 平仓价格始终使用买1/卖1
|
||||
const closeBidPrice = formatPriceToString(finalBid, priceDecimals);
|
||||
const closeAskPrice = formatPriceToString(finalAsk, priceDecimals);
|
||||
const rawBidPrice = finalBid - this.config.bidOffset;
|
||||
const rawAskPrice = finalAsk + this.config.askOffset;
|
||||
|
||||
// 开仓价格根据 entryDepthLevel 使用指定档位
|
||||
const entryLevel = this.config.entryDepthLevel ?? 1;
|
||||
const { bidAtLevel: entryBid, askAtLevel: entryAsk } = getPricesAtLevel(latestDepth, entryLevel);
|
||||
const entryBidBase = entryBid ?? finalBid;
|
||||
const entryAskBase = entryAsk ?? finalAsk;
|
||||
|
||||
const rawBidPrice = entryBidBase - this.config.bidOffset;
|
||||
const rawAskPrice = entryAskBase + this.config.askOffset;
|
||||
const safeBid = this.ensureMakerPrice("BUY", rawBidPrice, finalBid, finalAsk);
|
||||
const safeAsk = this.ensureMakerPrice("SELL", rawAskPrice, finalBid, finalAsk);
|
||||
const bidPrice = safeBid != null ? formatPriceToString(safeBid, priceDecimals) : null;
|
||||
|
||||
@@ -14,7 +14,7 @@ import { isOrderActiveStatus } from "../utils/order-status";
|
||||
import { getPosition } from "../utils/strategy";
|
||||
import type { PositionSnapshot } from "../utils/strategy";
|
||||
import { computePositionPnl } from "../utils/pnl";
|
||||
import { getTopPrices, getMidOrLast } from "../utils/price";
|
||||
import { getTopPrices, getPricesAtLevel, getMidOrLast } from "../utils/price";
|
||||
import { shouldStopLoss } from "../utils/risk";
|
||||
import {
|
||||
marketClose,
|
||||
@@ -305,10 +305,18 @@ export class MakerEngine {
|
||||
|
||||
// 直接使用orderbook价格,格式化为字符串避免精度问题
|
||||
const priceDecimals = this.getPriceDecimals();
|
||||
// 平仓价格始终使用买1/卖1
|
||||
const closeBidPrice = formatPriceToString(topBid, priceDecimals);
|
||||
const closeAskPrice = formatPriceToString(topAsk, priceDecimals);
|
||||
const bidPrice = formatPriceToString(topBid - this.config.bidOffset, priceDecimals);
|
||||
const askPrice = formatPriceToString(topAsk + this.config.askOffset, priceDecimals);
|
||||
|
||||
// 开仓价格根据 entryDepthLevel 使用指定档位
|
||||
const entryLevel = this.config.entryDepthLevel ?? 1;
|
||||
const { bidAtLevel: entryBid, askAtLevel: entryAsk } = getPricesAtLevel(depth, entryLevel);
|
||||
const entryBidBase = entryBid ?? topBid;
|
||||
const entryAskBase = entryAsk ?? topAsk;
|
||||
|
||||
const bidPrice = formatPriceToString(entryBidBase - this.config.bidOffset, priceDecimals);
|
||||
const askPrice = formatPriceToString(entryAskBase + this.config.askOffset, priceDecimals);
|
||||
const position = getPosition(this.accountSnapshot, this.config.symbol);
|
||||
const absPosition = Math.abs(position.positionAmt);
|
||||
const desired: DesiredOrder[] = [];
|
||||
|
||||
@@ -15,7 +15,7 @@ import { getPosition, parseSymbolParts } from "../utils/strategy";
|
||||
import type { PositionSnapshot } from "../utils/strategy";
|
||||
import { computeDepthStats } from "../utils/depth";
|
||||
import { computePositionPnl } from "../utils/pnl";
|
||||
import { getTopPrices, getMidOrLast } from "../utils/price";
|
||||
import { getTopPrices, getPricesAtLevel, getMidOrLast } from "../utils/price";
|
||||
import { shouldStopLoss } from "../utils/risk";
|
||||
import {
|
||||
marketClose,
|
||||
@@ -356,10 +356,18 @@ export class OffsetMakerEngine {
|
||||
|
||||
// 直接使用orderbook价格,格式化为字符串避免精度问题
|
||||
const priceDecimals = this.getPriceDecimals();
|
||||
// 平仓价格始终使用买1/卖1
|
||||
const closeBidPrice = formatPriceToString(finalBid, priceDecimals);
|
||||
const closeAskPrice = formatPriceToString(finalAsk, priceDecimals);
|
||||
const rawBidPrice = finalBid - this.config.bidOffset;
|
||||
const rawAskPrice = finalAsk + this.config.askOffset;
|
||||
|
||||
// 开仓价格根据 entryDepthLevel 使用指定档位
|
||||
const entryLevel = this.config.entryDepthLevel ?? 1;
|
||||
const { bidAtLevel: entryBid, askAtLevel: entryAsk } = getPricesAtLevel(latestDepth, entryLevel);
|
||||
const entryBidBase = entryBid ?? finalBid;
|
||||
const entryAskBase = entryAsk ?? finalAsk;
|
||||
|
||||
const rawBidPrice = entryBidBase - this.config.bidOffset;
|
||||
const rawAskPrice = entryAskBase + this.config.askOffset;
|
||||
const safeBid = this.ensureMakerPrice("BUY", rawBidPrice, finalBid, finalAsk);
|
||||
const safeAsk = this.ensureMakerPrice("SELL", rawAskPrice, finalBid, finalAsk);
|
||||
const bidPrice = safeBid != null ? formatPriceToString(safeBid, priceDecimals) : null;
|
||||
|
||||
@@ -9,6 +9,46 @@ export function getTopPrices(depth?: AsterDepth | null): { topBid: number | 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;
|
||||
|
||||
Reference in New Issue
Block a user