|
|
@@ -97,12 +97,39 @@ export class GridMaker {
|
|
|
this.logger.info({ mid, config: this.config, currentGridStepBps: this.currentGridStepBps }, 'Initializing grid');
|
|
|
|
|
|
const { gridRangeBps, maxLayers, baseClipUsd } = this.config;
|
|
|
+ const minLayers = this.adaptiveConfig?.minLayers;
|
|
|
+ const minGridStepBps = this.adaptiveConfig?.minGridStepBps ?? 0;
|
|
|
+ const maxGridStepBps = this.adaptiveConfig?.maxGridStepBps ?? Number.POSITIVE_INFINITY;
|
|
|
+
|
|
|
+ if (minLayers && minLayers > 0 && maxLayers < minLayers) {
|
|
|
+ this.logger.warn({
|
|
|
+ configuredMaxLayers: maxLayers,
|
|
|
+ requestedMinLayers: minLayers
|
|
|
+ }, 'Configured maxLayers is lower than adaptive minLayers; min layers target cannot be fully satisfied');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (minLayers && minLayers > 0) {
|
|
|
+ const maxStepForMinLayers = gridRangeBps / minLayers;
|
|
|
+ if (this.currentGridStepBps > maxStepForMinLayers) {
|
|
|
+ const adjustedStep = clamp(maxStepForMinLayers, minGridStepBps, maxGridStepBps);
|
|
|
+ if (adjustedStep < this.currentGridStepBps - 1e-6) {
|
|
|
+ this.logger.info({
|
|
|
+ previousStepBps: this.currentGridStepBps,
|
|
|
+ adjustedStepBps: adjustedStep,
|
|
|
+ minLayers
|
|
|
+ }, 'Reducing grid step to preserve minimum layer count');
|
|
|
+ this.currentGridStepBps = adjustedStep;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const stepRatio = this.currentGridStepBps / 1e4;
|
|
|
const rangeRatio = gridRangeBps / 1e4;
|
|
|
|
|
|
// 计算实际层数(不超过 maxLayers)
|
|
|
- const calculatedLayers = Math.floor(rangeRatio / stepRatio);
|
|
|
- const actualLayers = Math.min(calculatedLayers, maxLayers);
|
|
|
+ const calculatedLayers = Math.floor(rangeRatio / stepRatio + 1e-9);
|
|
|
+ const minLayerTarget = minLayers ? Math.min(minLayers, maxLayers) : 0;
|
|
|
+ const actualLayers = Math.max(Math.min(calculatedLayers, maxLayers), minLayerTarget);
|
|
|
|
|
|
// 计算单层订单大小(base asset)
|
|
|
const baseSz = baseClipUsd / mid;
|
|
|
@@ -112,7 +139,12 @@ export class GridMaker {
|
|
|
throw new Error(`Grid base size ${baseSz} rounded to zero with lot size ${this.lotSize}`);
|
|
|
}
|
|
|
|
|
|
- this.logger.info({ actualLayers, baseSz: normalizedBaseSz, gridStepBps: this.currentGridStepBps }, 'Grid parameters calculated');
|
|
|
+ this.logger.info({
|
|
|
+ actualLayers,
|
|
|
+ baseSz: normalizedBaseSz,
|
|
|
+ gridStepBps: this.currentGridStepBps,
|
|
|
+ minLayerTarget: minLayers
|
|
|
+ }, 'Grid parameters calculated');
|
|
|
|
|
|
// 重置连续失败计数
|
|
|
this.consecutivePlaceFailures = 0;
|
|
|
@@ -725,7 +757,8 @@ export class GridMaker {
|
|
|
maxVolatilityBps,
|
|
|
minGridStepBps,
|
|
|
maxGridStepBps,
|
|
|
- minStepChangeRatio
|
|
|
+ minStepChangeRatio,
|
|
|
+ minLayers
|
|
|
} = this.adaptiveConfig;
|
|
|
|
|
|
const clampedVol = clamp(hourlyVolBps, minVolatilityBps, maxVolatilityBps);
|
|
|
@@ -759,6 +792,22 @@ export class GridMaker {
|
|
|
let finalTargetStep = Math.max(targetStep, effectiveMinStep);
|
|
|
finalTargetStep = clamp(finalTargetStep, minGridStepBps, maxGridStepBps);
|
|
|
|
|
|
+ if (minLayers && minLayers > 0) {
|
|
|
+ const maxStepForMinLayers = this.config.gridRangeBps / minLayers;
|
|
|
+ if (finalTargetStep > maxStepForMinLayers) {
|
|
|
+ const adjusted = Math.max(minGridStepBps, Math.min(maxStepForMinLayers, maxGridStepBps));
|
|
|
+ if (adjusted < finalTargetStep - 1e-6) {
|
|
|
+ this.logger.info({
|
|
|
+ requestedStepBps: finalTargetStep,
|
|
|
+ adjustedStepBps: adjusted,
|
|
|
+ minLayers,
|
|
|
+ gridRangeBps: this.config.gridRangeBps
|
|
|
+ }, 'Limiting grid step to preserve minimum layer count');
|
|
|
+ }
|
|
|
+ finalTargetStep = adjusted;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const changeRatio = Math.abs(finalTargetStep - this.currentGridStepBps) / this.currentGridStepBps;
|
|
|
if (changeRatio < (minStepChangeRatio ?? 0.2)) {
|
|
|
this.logger.debug({
|
|
|
@@ -841,6 +890,7 @@ export interface AdaptiveGridConfig {
|
|
|
maxCadenceMs?: number;
|
|
|
hedgePendingTimeoutMs?: number;
|
|
|
postOnlyCushionBps?: number;
|
|
|
+ minLayers?: number;
|
|
|
}
|
|
|
|
|
|
function clamp(value: number, min: number, max: number): number {
|