mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-11 09:18:08 +00:00
refactor(strategy): extract PrecisionSyncer from 8 duplicated copies
Every engine hand-rolled the same ~35-line syncPrecision: fetch getPrecision(), compare against a 1e-12 epsilon, log, retry in 2s on failure. The copies had drifted — three bypassed i18n with hardcoded strings, maker-points alone supported a forced re-sync, and the maker family wrote this.qtyStep while trend/swing/guardian wrote config.qtyStep. Extract Class: PrecisionSyncer owns both increments plus min base/quote amounts and writes through to config, so both read styles keep working. Engines now hold one collaborator instead of four fields. Fixes a leak present in all eight copies: the 2s retry timer was never cleared, so an engine stopped mid-retry kept polling a dead adapter forever. stop() now cancels it — in the Ink UI that leaked one retry loop per strategy switch. Also collapses log.trend.precision*/log.guardian.precision* into log.common.* (the three key pairs held byte-identical text). 8 new tests; 226 pass; tsc --noEmit clean. -260 lines.
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
type PositionSnapshot,
|
||||
} from "../utils/strategy";
|
||||
import { StrategyEventEmitter } from "./common/event-emitter";
|
||||
import { createPrecisionSyncer, type PrecisionSyncer } from "./common/precision-syncer";
|
||||
import { safeSubscribe, type LogHandler } from "./common/subscriptions";
|
||||
import {
|
||||
placeStopLossOrder,
|
||||
@@ -64,11 +65,14 @@ export class GuardianEngine {
|
||||
price: null,
|
||||
at: 0,
|
||||
};
|
||||
private precisionSync: Promise<void> | null = null;
|
||||
private readonly precision: PrecisionSyncer;
|
||||
|
||||
constructor(private readonly config: TradingConfig, private readonly exchange: ExchangeAdapter) {
|
||||
this.tradeLog = createTradeLog(this.config.maxLogEntries);
|
||||
this.syncPrecision();
|
||||
this.precision = createPrecisionSyncer(this.exchange, this.config, this.config.qtyStep, (type, detail) =>
|
||||
this.tradeLog.push(type, detail)
|
||||
);
|
||||
this.precision.start();
|
||||
this.bootstrap();
|
||||
}
|
||||
|
||||
@@ -84,6 +88,7 @@ export class GuardianEngine {
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
this.precision.stop();
|
||||
}
|
||||
|
||||
on(event: GuardianEngineEvent, handler: GuardianEngineListener): void {
|
||||
@@ -651,42 +656,4 @@ export class GuardianEngine {
|
||||
return Math.max(0, Math.min(12, Math.floor(digits)));
|
||||
}
|
||||
|
||||
private syncPrecision(): void {
|
||||
if (this.precisionSync) return;
|
||||
const getPrecision = this.exchange.getPrecision?.bind(this.exchange);
|
||||
if (!getPrecision) return;
|
||||
this.precisionSync = getPrecision()
|
||||
.then((precision) => {
|
||||
if (!precision) return;
|
||||
let updated = false;
|
||||
if (Number.isFinite(precision.priceTick) && precision.priceTick > 0) {
|
||||
const delta = Math.abs(precision.priceTick - this.config.priceTick);
|
||||
if (delta > 1e-12) {
|
||||
this.config.priceTick = precision.priceTick;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (Number.isFinite(precision.qtyStep) && precision.qtyStep > 0) {
|
||||
const delta = Math.abs(precision.qtyStep - this.config.qtyStep);
|
||||
if (delta > 1e-12) {
|
||||
this.config.qtyStep = precision.qtyStep;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (updated) {
|
||||
this.tradeLog.push(
|
||||
"info",
|
||||
t("log.guardian.precisionSynced", {
|
||||
priceTick: precision.priceTick,
|
||||
qtyStep: precision.qtyStep,
|
||||
})
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.tradeLog.push("error", t("log.guardian.precisionFailed", { error: extractMessage(error) }));
|
||||
this.precisionSync = null;
|
||||
setTimeout(() => this.syncPrecision(), 2000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user