@senpi/runtime 3.0.118 → 3.0.123
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
- package/dist/actions/open-position/open-position.action.js +9 -0
- package/dist/actions/open-position/open-position.action.js.map +1 -1
- package/dist/cli/guide-commands.d.ts.map +1 -1
- package/dist/cli/guide-commands.js +16 -8
- package/dist/cli/guide-commands.js.map +1 -1
- package/dist/constants/dsl/index.d.ts +17 -6
- package/dist/constants/dsl/index.d.ts.map +1 -1
- package/dist/constants/dsl/index.js +17 -6
- package/dist/constants/dsl/index.js.map +1 -1
- package/dist/dsl/engine/floors.d.ts +25 -1
- package/dist/dsl/engine/floors.d.ts.map +1 -1
- package/dist/dsl/engine/floors.js +38 -6
- package/dist/dsl/engine/floors.js.map +1 -1
- package/dist/dsl/engine/index.d.ts +1 -1
- package/dist/dsl/engine/index.d.ts.map +1 -1
- package/dist/dsl/engine/index.js +1 -1
- package/dist/dsl/engine/index.js.map +1 -1
- package/dist/dsl/engine/round.d.ts +22 -2
- package/dist/dsl/engine/round.d.ts.map +1 -1
- package/dist/dsl/engine/round.js +78 -5
- package/dist/dsl/engine/round.js.map +1 -1
- package/dist/dsl/engine/tick.d.ts.map +1 -1
- package/dist/dsl/engine/tick.js +31 -16
- package/dist/dsl/engine/tick.js.map +1 -1
- package/dist/dsl/events/initial-state.d.ts +1 -1
- package/dist/dsl/events/initial-state.d.ts.map +1 -1
- package/dist/dsl/events/initial-state.js +4 -7
- package/dist/dsl/events/initial-state.js.map +1 -1
- package/dist/dsl/monitor/exchange-sync.d.ts +8 -3
- package/dist/dsl/monitor/exchange-sync.d.ts.map +1 -1
- package/dist/dsl/monitor/exchange-sync.js +16 -4
- package/dist/dsl/monitor/exchange-sync.js.map +1 -1
- package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
- package/dist/dsl/monitor/process-one-position.js +88 -3
- package/dist/dsl/monitor/process-one-position.js.map +1 -1
- package/dist/dsl/plugin/index.d.ts +8 -4
- package/dist/dsl/plugin/index.d.ts.map +1 -1
- package/dist/dsl/plugin/index.js +8 -4
- package/dist/dsl/plugin/index.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +168 -7
- package/dist/index.js.map +1 -1
- package/dist/runtime/boot-skip.d.ts +73 -0
- package/dist/runtime/boot-skip.d.ts.map +1 -0
- package/dist/runtime/boot-skip.js +113 -0
- package/dist/runtime/boot-skip.js.map +1 -0
- package/dist/runtime/create-runtime-context.d.ts +2 -0
- package/dist/runtime/create-runtime-context.d.ts.map +1 -1
- package/dist/runtime/create-runtime-context.js +1 -0
- package/dist/runtime/create-runtime-context.js.map +1 -1
- package/dist/runtime/lifecycle-events.d.ts +42 -1
- package/dist/runtime/lifecycle-events.d.ts.map +1 -1
- package/dist/runtime/lifecycle-events.js +81 -1
- package/dist/runtime/lifecycle-events.js.map +1 -1
- package/dist/runtime/lifecycle-reaper.d.ts +202 -0
- package/dist/runtime/lifecycle-reaper.d.ts.map +1 -0
- package/dist/runtime/lifecycle-reaper.js +390 -0
- package/dist/runtime/lifecycle-reaper.js.map +1 -0
- package/dist/runtime/run.d.ts +5 -0
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +1 -0
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/runtime.d.ts +2 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +1 -0
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/update-apply-deps.d.ts +23 -2
- package/dist/runtime/update-apply-deps.d.ts.map +1 -1
- package/dist/runtime/update-apply-deps.js +11 -5
- package/dist/runtime/update-apply-deps.js.map +1 -1
- package/dist/skills-manager/manifest.d.ts.map +1 -1
- package/dist/skills-manager/manifest.js +1 -0
- package/dist/skills-manager/manifest.js.map +1 -1
- package/dist/skills-manager/skills-manifest.json +1 -0
- package/dist/types/dsl/index.d.ts +1 -1
- package/dist/types/dsl/index.d.ts.map +1 -1
- package/dist/types/runtime.d.ts +8 -0
- package/dist/types/runtime.d.ts.map +1 -1
- package/dist/utils/event-catalog.d.ts +91 -0
- package/dist/utils/event-catalog.d.ts.map +1 -1
- package/dist/utils/event-catalog.js +13 -0
- package/dist/utils/event-catalog.js.map +1 -1
- package/dist/utils/keyed-mutex.d.ts +3 -2
- package/dist/utils/keyed-mutex.d.ts.map +1 -1
- package/dist/utils/keyed-mutex.js +3 -2
- package/dist/utils/keyed-mutex.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/dsl/engine/round.js
CHANGED
|
@@ -1,9 +1,82 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Rounding for DSL protective price levels (stops).
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
/** Hyperliquid's price rule: significant figures, then a per-asset decimal cap. */
|
|
5
|
+
const SIG_FIGS = 5;
|
|
6
|
+
/**
|
|
7
|
+
* `6 - szDecimals` is the perp decimal cap; 6 is its loosest value and the runtime has no
|
|
8
|
+
* per-asset `szDecimals`, so this is the tightest bound we can assert without one.
|
|
9
|
+
*/
|
|
10
|
+
const MAX_DECIMALS = 6;
|
|
11
|
+
/** Decimal exponent of `value`, read off its shortest exponential form so no rounding can bump it. */
|
|
12
|
+
function decimalExponent(value) {
|
|
13
|
+
const s = value.toExponential();
|
|
14
|
+
return Number(s.slice(s.indexOf("e") + 1));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Quantise to `SIG_FIGS`, biased away from the mark.
|
|
18
|
+
*
|
|
19
|
+
* `Number(value.toPrecision(n))` is used rather than `Math.floor(value * 10 ** k)` because the
|
|
20
|
+
* latter carries binary floating-point artifacts (`8.29 * 1e4 === 82899.99999999999`) that
|
|
21
|
+
* silently drift the level by a tick. `toPrecision` gives the NEAREST grid value; we step one
|
|
22
|
+
* unit in the last place only when that landed on the wrong side.
|
|
23
|
+
*/
|
|
24
|
+
function toSignificantFigures(value, roundDown) {
|
|
25
|
+
const nearest = Number(value.toPrecision(SIG_FIGS));
|
|
26
|
+
if (nearest === value)
|
|
27
|
+
return value;
|
|
28
|
+
const ulp = 10 ** (decimalExponent(value) - (SIG_FIGS - 1));
|
|
29
|
+
if (roundDown && nearest > value)
|
|
30
|
+
return Number((nearest - ulp).toPrecision(SIG_FIGS));
|
|
31
|
+
if (!roundDown && nearest < value)
|
|
32
|
+
return Number((nearest + ulp).toPrecision(SIG_FIGS));
|
|
33
|
+
return nearest;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Quantise to `MAX_DECIMALS`, biased away from the mark. Same nearest-then-step approach.
|
|
37
|
+
*
|
|
38
|
+
* Below the 1e-6 grid there is no representable protective level at all: rounding down gives 0,
|
|
39
|
+
* which is no stop, and rounding up gives 1e-6, which for a SHORT can sit multiples above the
|
|
40
|
+
* level asked for. Both are worse than passing the significant-figure value through and letting
|
|
41
|
+
* the venue's own validation answer. No Hyperliquid perp trades there, so this is a deliberate
|
|
42
|
+
* decision about an unreachable input rather than a supported price range — and it is why the
|
|
43
|
+
* "at most 6 decimals" guarantee is stated for inputs at or above 1e-6.
|
|
44
|
+
*/
|
|
45
|
+
function toMaxDecimals(value, roundDown) {
|
|
46
|
+
const scale = 10 ** MAX_DECIMALS;
|
|
47
|
+
if (value < 1 / scale)
|
|
48
|
+
return value;
|
|
49
|
+
let units = Math.round(Number(value.toFixed(MAX_DECIMALS)) * scale);
|
|
50
|
+
if (roundDown && units / scale > value)
|
|
51
|
+
units -= 1;
|
|
52
|
+
if (!roundDown && units / scale < value)
|
|
53
|
+
units += 1;
|
|
54
|
+
return units / scale;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Round a protective price level onto Hyperliquid's price grid, biased AWAY from the mark.
|
|
58
|
+
*
|
|
59
|
+
* A LONG's stop sits below the mark so it rounds down; a SHORT's sits above so it rounds up.
|
|
60
|
+
* THIS service's rounding may then only ever loosen a stop, never tighten it and never move it
|
|
61
|
+
* across the mark: the trading engine rejects `slTriggerPrice >= currentPrice` for a LONG (and
|
|
62
|
+
* `<=` for a SHORT) as "would execute immediately", and a rejected stop leaves the position with
|
|
63
|
+
* no exchange-side protection at all.
|
|
64
|
+
*
|
|
65
|
+
* It is not an end-to-end guarantee. The trading engine re-rounds what we send with
|
|
66
|
+
* `roundToDecimals(price, 6 - szDecimals)`, which is round-to-NEAREST (`utils.go:133-136`), so
|
|
67
|
+
* for an asset whose `szDecimals` forces fewer than 6 decimals it can still move a LONG floor
|
|
68
|
+
* back up by half a venue tick. Reading per-asset `szDecimals` is what would close that; until
|
|
69
|
+
* then the residual degrades to a rejection, which the phase-2 breach path now turns into an
|
|
70
|
+
* exit rather than a silent no-stop.
|
|
71
|
+
*
|
|
72
|
+
* Non-finite, zero and negative inputs are returned unchanged — there is no meaningful grid
|
|
73
|
+
* for them, and silently manufacturing a level would be worse than passing the caller's own
|
|
74
|
+
* value through to its validation.
|
|
75
|
+
*/
|
|
76
|
+
export function roundProtectiveLevel(value, direction) {
|
|
77
|
+
if (!Number.isFinite(value) || value <= 0)
|
|
78
|
+
return value;
|
|
79
|
+
const roundDown = direction === "LONG";
|
|
80
|
+
return toMaxDecimals(toSignificantFigures(value, roundDown), roundDown);
|
|
8
81
|
}
|
|
9
82
|
//# sourceMappingURL=round.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"round.js","sourceRoot":"","sources":["../../../src/dsl/engine/round.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"round.js","sourceRoot":"","sources":["../../../src/dsl/engine/round.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,mFAAmF;AACnF,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB;;;GAGG;AACH,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB,sGAAsG;AACtG,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;IAChC,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,oBAAoB,CAAC,KAAa,EAAE,SAAkB;IAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5D,IAAI,SAAS,IAAI,OAAO,GAAG,KAAK;QAAE,OAAO,MAAM,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvF,IAAI,CAAC,SAAS,IAAI,OAAO,GAAG,KAAK;QAAE,OAAO,MAAM,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,aAAa,CAAC,KAAa,EAAE,SAAkB;IACtD,MAAM,KAAK,GAAG,EAAE,IAAI,YAAY,CAAC;IACjC,IAAI,KAAK,GAAG,CAAC,GAAG,KAAK;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;IACpE,IAAI,SAAS,IAAI,KAAK,GAAG,KAAK,GAAG,KAAK;QAAE,KAAK,IAAI,CAAC,CAAC;IACnD,IAAI,CAAC,SAAS,IAAI,KAAK,GAAG,KAAK,GAAG,KAAK;QAAE,KAAK,IAAI,CAAC,CAAC;IACpD,OAAO,KAAK,GAAG,KAAK,CAAC;AACvB,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAa,EAAE,SAA2B;IAC7E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACxD,MAAM,SAAS,GAAG,SAAS,KAAK,MAAM,CAAC;IACvC,OAAO,aAAa,CAAC,oBAAoB,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tick.d.ts","sourceRoot":"","sources":["../../../src/dsl/engine/tick.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"tick.d.ts","sourceRoot":"","sources":["../../../src/dsl/engine/tick.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAgBxE,wBAAgB,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAwNlF"}
|
package/dist/dsl/engine/tick.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Pure DSL tick: state + price → next state and actions.
|
|
3
3
|
*/
|
|
4
4
|
import { CLOSE_REASON } from "../../constants/dsl/index.js";
|
|
5
|
-
import { computeCurrentROE, computeTierFloor, effectiveFloor, isBreach, resolveBreachesRequired, tierIndexFromPrice, } from "./floors.js";
|
|
5
|
+
import { computeCurrentROE, computeTierFloor, effectiveFloor, hasRestingStopAtFloor, isBreach, resolveBreachesRequired, tierIndexFromPrice, } from "./floors.js";
|
|
6
6
|
import { updateHighWater, writeDerivedFields } from "./state-updates.js";
|
|
7
7
|
import { createLogger } from "../../utils/logger.js";
|
|
8
8
|
const log = createLogger("[senpi-core][dsl-tick]");
|
|
@@ -25,23 +25,38 @@ export function dslTick(state, price, now) {
|
|
|
25
25
|
let closeReason;
|
|
26
26
|
const newTierIndexForBreach = tierIndexFromPrice(next, price);
|
|
27
27
|
const prevTierIndexForBreach = next.currentTierIndex ?? -1;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
// Breach detection runs in BOTH phases. In phase 2 the exchange stop is normally what exits,
|
|
29
|
+
// but a stop the venue rejected (a level rounded onto the mark, say) leaves the floor on the
|
|
30
|
+
// wrong side of the mark with nothing resting behind it — which is a breach by definition, and
|
|
31
|
+
// dsl-engine cannot close a position, so the runtime is the only thing that can. This sits
|
|
32
|
+
// ahead of the `handoffStatus === "ok"` early return so a backend-owned position surfaces a
|
|
33
|
+
// breach too; `consecutiveBreachesRequired` still gives a resting stop time to fill first.
|
|
34
|
+
//
|
|
35
|
+
// The breach is COUNTED either way; only the close is withheld when a stop is already resting
|
|
36
|
+
// at the floor. Raising a close there would return at the `action === "close"` early return
|
|
37
|
+
// below, which skips the time cuts, the tier advance and the floor recompute — and the whole
|
|
38
|
+
// downstream half of the monitor tick, SL sync and heartbeat included — on every tick the mark
|
|
39
|
+
// spends at or under the floor. A stale `slOrderId` (a stop cancelled at the venue is never
|
|
40
|
+
// cleared, since the tick's `getOrderStatus` check only clears on `filled`) would then take
|
|
41
|
+
// `hard_timeout` down with it.
|
|
42
|
+
if (isBreach(next, price)) {
|
|
43
|
+
const breachesRequired = resolveBreachesRequired(next);
|
|
44
|
+
// Clamped at the threshold. In phase 1 the close bounded this; in phase 2 a withheld close
|
|
45
|
+
// does not, and an unbounded counter renders as `18432/1` in `senpi dsl` and fires the
|
|
46
|
+
// `breach_detected` span event on every tick it grows.
|
|
47
|
+
const newCount = Math.min((next.currentBreachCount ?? 0) + 1, breachesRequired);
|
|
48
|
+
next = { ...next, currentBreachCount: newCount };
|
|
49
|
+
if (newCount >= breachesRequired && !hasRestingStopAtFloor(next)) {
|
|
50
|
+
action = "close";
|
|
51
|
+
closeReason = CLOSE_REASON.DSL_BREACH;
|
|
52
|
+
next = { ...next, floorPrice: prevFloorPrice };
|
|
43
53
|
}
|
|
44
54
|
}
|
|
55
|
+
else {
|
|
56
|
+
const advancingTier = newTierIndexForBreach > prevTierIndexForBreach;
|
|
57
|
+
if (!advancingTier)
|
|
58
|
+
next = { ...next, currentBreachCount: 0 };
|
|
59
|
+
}
|
|
45
60
|
if (action === "none") {
|
|
46
61
|
const currentROE = computeCurrentROE(next, price);
|
|
47
62
|
if (next.hardTimeout?.enabled) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tick.js","sourceRoot":"","sources":["../../../src/dsl/engine/tick.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,QAAQ,EACR,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,GAAG,GAAG,YAAY,CAAC,wBAAwB,CAAC,CAAC;AAEnD,MAAM,UAAU,OAAO,CAAC,KAAe,EAAE,KAAa,EAAE,GAAW;IACjE,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAAC;IACxC,IAAI,IAAI,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAE9C,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzD,IAAI,IAAI,CAAC,WAAW,EAAE,OAAO,IAAI,iBAAiB,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;QAChF,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,oBAAoB,EAAE,GAAG,EAAE,CAAC;IAChD,CAAC;IACD,oGAAoG;IACpG,gGAAgG;IAChG,mGAAmG;IACnG,IAAI,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,iBAAiB,GAAG,CAAC,EAAE,CAAC;QACzD,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,sBAAsB,EAAE,GAAG,EAAE,CAAC;IAClD,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAEjC,IAAI,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,MAAM,GAA4B,MAAM,CAAC;IAC7C,IAAI,WAA+B,CAAC;IAEpC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC9D,MAAM,sBAAsB,GAAG,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC;IAE3D,
|
|
1
|
+
{"version":3,"file":"tick.js","sourceRoot":"","sources":["../../../src/dsl/engine/tick.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,6 @@ export interface NotifiedStopCarry {
|
|
|
22
22
|
/** Breakeven latch; once true the "you can no longer lose" push is spent. */
|
|
23
23
|
stopBreakevenAnnounced?: boolean;
|
|
24
24
|
}
|
|
25
|
-
export declare function phase1FloorFromPreset(entryPrice: number, direction:
|
|
25
|
+
export declare function phase1FloorFromPreset(entryPrice: number, direction: "LONG" | "SHORT", maxLossPct: number, leverage: number): number;
|
|
26
26
|
export declare function buildInitialState(event: PositionOpenedEvent, preset: DslPluginConfig["presets"][string], phase1Floor: number, triggerReason: DslCreatedTriggerReason, carry?: NotifiedStopCarry): DslState;
|
|
27
27
|
//# sourceMappingURL=initial-state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initial-state.d.ts","sourceRoot":"","sources":["../../../src/dsl/events/initial-state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,uBAAuB,EACvB,eAAe,EACf,QAAQ,EACR,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"initial-state.d.ts","sourceRoot":"","sources":["../../../src/dsl/events/initial-state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,uBAAuB,EACvB,eAAe,EACf,QAAQ,EACR,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAQlC;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uEAAuE;IACvE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAAG,OAAO,EAC3B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAIR;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,mBAAmB,EAC1B,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EAC1C,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,uBAAuB,EACtC,KAAK,CAAC,EAAE,iBAAiB,GACxB,QAAQ,CA8FV"}
|
|
@@ -2,19 +2,16 @@
|
|
|
2
2
|
* Build initial DslState from position.opened event and resolved preset.
|
|
3
3
|
*/
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
|
-
import { DSL_STATE_VERSION
|
|
5
|
+
import { DSL_STATE_VERSION } from "../../constants/dsl/index.js";
|
|
6
|
+
import { roundProtectiveLevel } from "../engine/round.js";
|
|
6
7
|
function now() {
|
|
7
8
|
return new Date().toISOString();
|
|
8
9
|
}
|
|
9
|
-
function round(v, d) {
|
|
10
|
-
const f = 10 ** d;
|
|
11
|
-
return Math.round(v * f) / f;
|
|
12
|
-
}
|
|
13
10
|
export function phase1FloorFromPreset(entryPrice, direction, maxLossPct, leverage) {
|
|
14
11
|
const pct = maxLossPct / 100 / leverage;
|
|
15
12
|
if (direction === "LONG")
|
|
16
|
-
return
|
|
17
|
-
return
|
|
13
|
+
return roundProtectiveLevel(entryPrice * (1 - pct), direction);
|
|
14
|
+
return roundProtectiveLevel(entryPrice * (1 + pct), direction);
|
|
18
15
|
}
|
|
19
16
|
export function buildInitialState(event, preset, phase1Floor, triggerReason, carry) {
|
|
20
17
|
const asset = event.coin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initial-state.js","sourceRoot":"","sources":["../../../src/dsl/events/initial-state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,OAAO,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"initial-state.js","sourceRoot":"","sources":["../../../src/dsl/events/initial-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,14 @@
|
|
|
2
2
|
* When to call editPosition to align exchange SL with dsl.engine exchangeStopLossTriggerPx.
|
|
3
3
|
*/
|
|
4
4
|
import type { DslState, DslTickResult } from "../../types/dsl/index.js";
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Minimum relative delta vs trigger price (0.0001 = 0.01%) so high-priced assets do not spam
|
|
7
|
+
* edits. Purely relative on purpose: this used to be `max(0.0001 USD, 0.01%)`, and the absolute
|
|
8
|
+
* term won that max for every asset under $1 — 2.5% of PUMP's price, 11% of BOME's — so on a
|
|
9
|
+
* cheap coin no ratchet short of a double-digit move re-synced and the trailing stop stayed
|
|
10
|
+
* frozen at whatever level it was first placed at, which is the one place the user needs it to
|
|
11
|
+
* move.
|
|
12
|
+
*/
|
|
8
13
|
export declare const SL_SYNC_MIN_DELTA_RELATIVE = 0.0001;
|
|
9
14
|
/**
|
|
10
15
|
* Whether to call `editPosition` to align the exchange SL with `exchangeStopLossTriggerPx`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exchange-sync.d.ts","sourceRoot":"","sources":["../../../src/dsl/monitor/exchange-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGxE
|
|
1
|
+
{"version":3,"file":"exchange-sync.d.ts","sourceRoot":"","sources":["../../../src/dsl/monitor/exchange-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGxE;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,SAAS,CAAC;AAYjD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAcnF"}
|
|
@@ -2,12 +2,24 @@
|
|
|
2
2
|
* When to call editPosition to align exchange SL with dsl.engine exchangeStopLossTriggerPx.
|
|
3
3
|
*/
|
|
4
4
|
import { exchangeStopLossTriggerPx } from "../engine/exchange-stop.js";
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Minimum relative delta vs trigger price (0.0001 = 0.01%) so high-priced assets do not spam
|
|
7
|
+
* edits. Purely relative on purpose: this used to be `max(0.0001 USD, 0.01%)`, and the absolute
|
|
8
|
+
* term won that max for every asset under $1 — 2.5% of PUMP's price, 11% of BOME's — so on a
|
|
9
|
+
* cheap coin no ratchet short of a double-digit move re-synced and the trailing stop stayed
|
|
10
|
+
* frozen at whatever level it was first placed at, which is the one place the user needs it to
|
|
11
|
+
* move.
|
|
12
|
+
*/
|
|
8
13
|
export const SL_SYNC_MIN_DELTA_RELATIVE = 0.0001;
|
|
9
14
|
function slSyncMinDeltaForPrice(triggerPx) {
|
|
10
|
-
|
|
15
|
+
// A non-positive trigger has no relative scale to measure against. Unreachable on any live
|
|
16
|
+
// path — `exchangeStopLossTriggerPx` returns a floor derived from a positive entry price —
|
|
17
|
+
// and the choice between the two behaviours is academic: 0 re-sends `triggerPx: 0` to the
|
|
18
|
+
// venue every tick, and Infinity freezes the stop. 0 is kept because a venue rejection is
|
|
19
|
+
// visible in `slSyncFailureCount` and the logs, where a frozen stop is silent.
|
|
20
|
+
if (!(triggerPx > 0))
|
|
21
|
+
return 0;
|
|
22
|
+
return triggerPx * SL_SYNC_MIN_DELTA_RELATIVE;
|
|
11
23
|
}
|
|
12
24
|
/**
|
|
13
25
|
* Whether to call `editPosition` to align the exchange SL with `exchangeStopLossTriggerPx`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exchange-sync.js","sourceRoot":"","sources":["../../../src/dsl/monitor/exchange-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAEvE
|
|
1
|
+
{"version":3,"file":"exchange-sync.js","sourceRoot":"","sources":["../../../src/dsl/monitor/exchange-sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAEvE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAEjD,SAAS,sBAAsB,CAAC,SAAiB;IAC/C,2FAA2F;IAC3F,2FAA2F;IAC3F,0FAA0F;IAC1F,0FAA0F;IAC1F,+EAA+E;IAC/E,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,SAAS,GAAG,0BAA0B,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAqB,EAAE,IAAc;IACxE,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9C,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,IAAI,MAAM,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,yFAAyF;QACzF,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IACvC,MAAM,SAAS,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,oBAAoB,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;AAC3E,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-one-position.d.ts","sourceRoot":"","sources":["../../../src/dsl/monitor/process-one-position.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAkB,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAqBzD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAiB/C;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,CAAC,EAAE,QAAQ,GACV;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAYvD;AAuGD,MAAM,WAAW,qBAAqB;IACpC,4FAA4F;IAC5F,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,GAAG,EAAE,aAAa,CAAC;IACnB,uBAAuB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACnD,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,sBAAsB,EAAE,cAAc,CAAC;IAC/D,oDAAoD;IACpD,wBAAwB,CAAC,EAAE,OAAO,sBAAsB,EAAE,wBAAwB,CAAC;CACpF;
|
|
1
|
+
{"version":3,"file":"process-one-position.d.ts","sourceRoot":"","sources":["../../../src/dsl/monitor/process-one-position.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAkB,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAqBzD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAiB/C;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,CAAC,EAAE,QAAQ,GACV;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAYvD;AAuGD,MAAM,WAAW,qBAAqB;IACpC,4FAA4F;IAC5F,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,GAAG,EAAE,aAAa,CAAC;IACnB,uBAAuB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACnD,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,sBAAsB,EAAE,cAAc,CAAC;IAC/D,oDAAoD;IACpD,wBAAwB,CAAC,EAAE,OAAO,sBAAsB,EAAE,wBAAwB,CAAC;CACpF;AAiCD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,qBAAqB,EAC1B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,IAAI,CAAC,CA8zBf"}
|
|
@@ -109,6 +109,36 @@ function failureContext(state, tickId) {
|
|
|
109
109
|
tickId,
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Venue statuses that mean the stop is definitively GONE from the book — cancelled by the user,
|
|
114
|
+
* by the venue, or rejected outright.
|
|
115
|
+
*
|
|
116
|
+
* Must stay in step with the backend's `classifySLOrderStatus`
|
|
117
|
+
* (dsl-engine `pkg/service/sl_order_status.go`). Deliberately NOT the inverse of
|
|
118
|
+
* `LIVE_VENUE_SL_STATUSES`: "not known-live" is a far bigger set than "known-dead" — it holds
|
|
119
|
+
* every status we have not seen yet, plus the empty one — and treating an unfamiliar status as
|
|
120
|
+
* dead would have the runtime place a second stop on top of a live one. Anything unlisted is
|
|
121
|
+
* UNKNOWN and changes nothing. Partially-filled and lifecycle-ended statuses are also not
|
|
122
|
+
* "gone": the fill check above and the reconcile path own those.
|
|
123
|
+
*/
|
|
124
|
+
const GONE_VENUE_SL_STATUSES = new Set([
|
|
125
|
+
"canceled",
|
|
126
|
+
"cancelled",
|
|
127
|
+
"margincanceled",
|
|
128
|
+
"selftradecanceled",
|
|
129
|
+
"openinterestcapcanceled",
|
|
130
|
+
"vaultwithdrawalcanceled",
|
|
131
|
+
"scheduledcancel",
|
|
132
|
+
]);
|
|
133
|
+
function isGoneVenueSlStatus(status) {
|
|
134
|
+
if (status == null)
|
|
135
|
+
return false;
|
|
136
|
+
// `parseExecutionOrderStatus` already lowercases; normalise again so a caller that does not
|
|
137
|
+
// cannot silently turn a cancellation into an unknown. Trim as well as lowercase, so this
|
|
138
|
+
// matches dsl-engine `normalizeOrderStatus` exactly rather than approximately.
|
|
139
|
+
const s = status.trim().toLowerCase();
|
|
140
|
+
return GONE_VENUE_SL_STATUSES.has(s) || s.endsWith("rejected");
|
|
141
|
+
}
|
|
112
142
|
export async function processOnePosition(ctx, key, state, price, span) {
|
|
113
143
|
const { tickId, ts, now: isoNow, stateManager, strategyStates, bus, isSlPlacementInProgress = () => false } = ctx;
|
|
114
144
|
const strategy = strategyStates.get(state.address);
|
|
@@ -176,6 +206,26 @@ export async function processOnePosition(ctx, key, state, price, span) {
|
|
|
176
206
|
}));
|
|
177
207
|
return;
|
|
178
208
|
}
|
|
209
|
+
if (isGoneVenueSlStatus(status?.status)) {
|
|
210
|
+
// The stop is off the book but the position is still open, and nothing else clears the
|
|
211
|
+
// id: `shouldSyncExchangeSl` short-circuits while `slOrderId != null`, and
|
|
212
|
+
// `hasRestingStopAtFloor` reads it as protection. Left alone, the position runs to
|
|
213
|
+
// liquidation with the breach counter pinned. Clearing BOTH fields re-arms it on this
|
|
214
|
+
// same tick — the id makes the sync fire, the floor makes the breach check honest.
|
|
215
|
+
// Same manoeuvre as dsl-engine's `rearmGoneStop`.
|
|
216
|
+
logger.warn("[dsl] exchange SL is gone from the venue, re-arming", {
|
|
217
|
+
tickId,
|
|
218
|
+
key,
|
|
219
|
+
asset: state.asset,
|
|
220
|
+
slOrderId: state.slOrderId,
|
|
221
|
+
lastSyncedFloorPrice: state.lastSyncedFloorPrice,
|
|
222
|
+
venueStatus: status?.status ?? null,
|
|
223
|
+
phase: state.phase,
|
|
224
|
+
});
|
|
225
|
+
recordDslDegradation({ failure: "sl_gone" });
|
|
226
|
+
await setIfStillActive(stateManager, key, state.address, state.asset, (current) => ({ ...current, slOrderId: null, lastSyncedFloorPrice: null }), { tickId, skipMessage: "[dsl] skip gone-SL clear: state already cleared (concurrent close)" });
|
|
227
|
+
state = { ...state, slOrderId: null, lastSyncedFloorPrice: null };
|
|
228
|
+
}
|
|
179
229
|
}
|
|
180
230
|
catch (e) {
|
|
181
231
|
logger.warn("getOrderStatus failed, skipping SL-hit check", { asset: state.asset, err: e });
|
|
@@ -366,13 +416,34 @@ export async function processOnePosition(ctx, key, state, price, span) {
|
|
|
366
416
|
span.setAttribute("senpi.dsl.current_roe", next.currentROE);
|
|
367
417
|
span.setAttribute("senpi.dsl.floor_price", next.floorPrice);
|
|
368
418
|
if (closeReasonToUse === CLOSE_REASON.DSL_BREACH && next.phase === 2) {
|
|
369
|
-
|
|
419
|
+
// Whether the resting exchange stop should be left to do the exiting is decided in
|
|
420
|
+
// `dslTick` (`hasRestingStopAtFloor`), so that a suppressed breach still runs the rest of
|
|
421
|
+
// the tick. Reaching here means no stop is resting at the floor.
|
|
422
|
+
//
|
|
423
|
+
// The position-opened handler may be mid-flight placing the initial stop; give it this
|
|
424
|
+
// tick. The SL-sync site has the same guard, but it runs after this close path.
|
|
425
|
+
if (isSlPlacementInProgress(key)) {
|
|
426
|
+
logger.info("[dsl] deferring phase 2 breach close: initial SL placement in progress", {
|
|
427
|
+
tickId,
|
|
428
|
+
key,
|
|
429
|
+
asset: state.asset,
|
|
430
|
+
floorPrice: next.floorPrice,
|
|
431
|
+
});
|
|
432
|
+
// dslTick stamped closeReason onto the state persisted above; the position is staying
|
|
433
|
+
// open, so clear it rather than leave a live position carrying a close reason.
|
|
434
|
+
await setIfStillActive(stateManager, key, state.address, state.asset, (current) => ({ ...current, closeReason: null }), { tickId, skipMessage: "[dsl] skip deferred-breach clear: state already cleared (concurrent close)" });
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
logger.warn("[dsl] phase 2 breach with no stop resting at the floor: closing from the runtime", {
|
|
370
438
|
tickId,
|
|
371
439
|
key,
|
|
372
440
|
asset: state.asset,
|
|
441
|
+
slOrderId: next.slOrderId,
|
|
442
|
+
lastSyncedFloorPrice: next.lastSyncedFloorPrice,
|
|
443
|
+
floorPrice: next.floorPrice,
|
|
444
|
+
handoffStatus: next.handoffStatus,
|
|
445
|
+
phase: next.phase,
|
|
373
446
|
});
|
|
374
|
-
await setIfStillActive(stateManager, key, state.address, state.asset, (current) => ({ ...current, closeReason: null }), { tickId, skipMessage: "[dsl] skip spurious-breach clear: state already cleared (concurrent close)" });
|
|
375
|
-
return;
|
|
376
447
|
}
|
|
377
448
|
logger.info("[dsl] dsl close: sending closePosition to exchange", {
|
|
378
449
|
tickId,
|
|
@@ -813,8 +884,18 @@ async function attemptHandoffRegistration(ctx, key, next, _original, strategy) {
|
|
|
813
884
|
adoptedId: adopted.id,
|
|
814
885
|
status: adopted.status,
|
|
815
886
|
});
|
|
887
|
+
// Mirror the backend's stop NOW, not on the next tick's handleHandoffOk poll. The
|
|
888
|
+
// phase-2 breach close at the top of the tick reads slOrderId / lastSyncedFloorPrice to
|
|
889
|
+
// decide whether anything is protecting this position, and it runs BEFORE handleHandoffOk
|
|
890
|
+
// — so leaving them at their phase-1 values for one tick means the next breach closes a
|
|
891
|
+
// position the backend is already protecting, racing its stop at the same price.
|
|
892
|
+
// Only those two fields: the tier/high-water state a just-created backend row reports is
|
|
893
|
+
// its own freshly evaluated view, and merging it here would walk back a local ratchet.
|
|
894
|
+
const adoptedSl = mapEnginePositionToStateFields(adopted);
|
|
816
895
|
const updated = {
|
|
817
896
|
...next,
|
|
897
|
+
slOrderId: adoptedSl.slOrderId,
|
|
898
|
+
lastSyncedFloorPrice: adoptedSl.lastSyncedFloorPrice,
|
|
818
899
|
handoffStatus: "ok",
|
|
819
900
|
backendDslPositionId: adopted.id,
|
|
820
901
|
lastBackendDslTick: ts,
|
|
@@ -874,8 +955,12 @@ async function attemptHandoffRegistration(ctx, key, next, _original, strategy) {
|
|
|
874
955
|
});
|
|
875
956
|
return;
|
|
876
957
|
}
|
|
958
|
+
// Mirror the backend's stop on the registration tick itself — see the adopt site above.
|
|
959
|
+
const registeredSl = mapEnginePositionToStateFields(result.position);
|
|
877
960
|
const updated = {
|
|
878
961
|
...next,
|
|
962
|
+
slOrderId: registeredSl.slOrderId,
|
|
963
|
+
lastSyncedFloorPrice: registeredSl.lastSyncedFloorPrice,
|
|
879
964
|
handoffStatus: "ok",
|
|
880
965
|
backendDslPositionId: result.position.id,
|
|
881
966
|
lastBackendDslTick: ts,
|