@senpi/runtime 3.0.171 → 3.0.173

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.
@@ -12,6 +12,23 @@ export declare function mapTiersToEngineConfig(tiers: DslTier[]): Array<{
12
12
  * locally until the backend confirms a real exchange stop.
13
13
  */
14
14
  export declare function parseSlOrderId(raw: string | null | undefined): number | null;
15
+ /**
16
+ * Backend position → the local state fields it owns once a position is handed off.
17
+ *
18
+ * `floorPrice` is included once a tier is engaged. After handoff the local tick returns before
19
+ * it recomputes the floor (`dslTick`'s `handoffStatus === "ok"` early return), so without this
20
+ * `floorPrice` stays at whatever it was at handoff: the phase-1 absolute floor for a position
21
+ * handed off at open (phase 1 disabled), or the first tier's floor for one handed off at the
22
+ * first tier. Two readers depend on it being the stop actually in force:
23
+ * - the breach safety net, which closes a backend-owned position when no stop is resting at
24
+ * the floor (`hasRestingStopAtFloor` compares it with `lastSyncedFloorPrice`);
25
+ * - the `plugin.senpi.strategies` telemetry, which the apps draw as the DSL line.
26
+ *
27
+ * It is set to the backend's floor exactly, never to the tighter of the two: a local floor
28
+ * tighter than the resting backend stop would read as "no stop at the floor" and the breach
29
+ * close would race that stop. Callers that must not walk back local tier state on the
30
+ * registration tick pick fields individually instead of spreading this.
31
+ */
15
32
  export declare function mapEnginePositionToStateFields(enginePos: DslEnginePosition): {
16
33
  currentTierIndex: number;
17
34
  tierFloorPrice: number;
@@ -19,5 +36,6 @@ export declare function mapEnginePositionToStateFields(enginePos: DslEnginePosit
19
36
  highWaterRoe: number;
20
37
  slOrderId: number | null;
21
38
  lastSyncedFloorPrice: number;
39
+ floorPrice?: number;
22
40
  };
23
41
  //# sourceMappingURL=config-mapping.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-mapping.d.ts","sourceRoot":"","sources":["../../../src/dsl/engine-client/config-mapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,oDAAoD;AACpD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EAAE,GACf,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAKhD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAM5E;AAED,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,iBAAiB,GAAG;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CASA"}
1
+ {"version":3,"file":"config-mapping.d.ts","sourceRoot":"","sources":["../../../src/dsl/engine-client/config-mapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,oDAAoD;AACpD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EAAE,GACf,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAKhD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAM5E;AAgBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,iBAAiB,GAAG;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAUA"}
@@ -20,6 +20,34 @@ export function parseSlOrderId(raw) {
20
20
  const id = Number(trimmed);
21
21
  return Number.isFinite(id) ? id : null;
22
22
  }
23
+ /**
24
+ * Whether the backend has engaged a tier, so its `tierFloorPrice` is the stop in force.
25
+ * Before the first tier dsl-engine reports `currentTierIndex: -1` and a null `tierFloorPrice`
26
+ * (its column defaults), and the position is still guarded by the phase-1 absolute floor.
27
+ */
28
+ function hasEngagedTier(enginePos) {
29
+ return (enginePos.currentTierIndex >= 0 &&
30
+ typeof enginePos.tierFloorPrice === "number" &&
31
+ Number.isFinite(enginePos.tierFloorPrice) &&
32
+ enginePos.tierFloorPrice > 0);
33
+ }
34
+ /**
35
+ * Backend position → the local state fields it owns once a position is handed off.
36
+ *
37
+ * `floorPrice` is included once a tier is engaged. After handoff the local tick returns before
38
+ * it recomputes the floor (`dslTick`'s `handoffStatus === "ok"` early return), so without this
39
+ * `floorPrice` stays at whatever it was at handoff: the phase-1 absolute floor for a position
40
+ * handed off at open (phase 1 disabled), or the first tier's floor for one handed off at the
41
+ * first tier. Two readers depend on it being the stop actually in force:
42
+ * - the breach safety net, which closes a backend-owned position when no stop is resting at
43
+ * the floor (`hasRestingStopAtFloor` compares it with `lastSyncedFloorPrice`);
44
+ * - the `plugin.senpi.strategies` telemetry, which the apps draw as the DSL line.
45
+ *
46
+ * It is set to the backend's floor exactly, never to the tighter of the two: a local floor
47
+ * tighter than the resting backend stop would read as "no stop at the floor" and the breach
48
+ * close would race that stop. Callers that must not walk back local tier state on the
49
+ * registration tick pick fields individually instead of spreading this.
50
+ */
23
51
  export function mapEnginePositionToStateFields(enginePos) {
24
52
  return {
25
53
  currentTierIndex: enginePos.currentTierIndex,
@@ -28,6 +56,7 @@ export function mapEnginePositionToStateFields(enginePos) {
28
56
  highWaterRoe: enginePos.highWaterRoe,
29
57
  slOrderId: parseSlOrderId(enginePos.activeSLOrderId),
30
58
  lastSyncedFloorPrice: enginePos.tierFloorPrice,
59
+ ...(hasEngagedTier(enginePos) ? { floorPrice: enginePos.tierFloorPrice } : {}),
31
60
  };
32
61
  }
33
62
  //# sourceMappingURL=config-mapping.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-mapping.js","sourceRoot":"","sources":["../../../src/dsl/engine-client/config-mapping.ts"],"names":[],"mappings":"AAGA,oDAAoD;AACpD,MAAM,UAAU,sBAAsB,CACpC,KAAgB;IAEhB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,OAAO,EAAE,CAAC,CAAC,SAAS;KACrB,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,GAA8B;IAC3D,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,SAA4B;IAQzE,OAAO;QACL,gBAAgB,EAAE,SAAS,CAAC,gBAAgB;QAC5C,cAAc,EAAE,SAAS,CAAC,cAAc;QACxC,cAAc,EAAE,SAAS,CAAC,cAAc;QACxC,YAAY,EAAE,SAAS,CAAC,YAAY;QACpC,SAAS,EAAE,cAAc,CAAC,SAAS,CAAC,eAAe,CAAC;QACpD,oBAAoB,EAAE,SAAS,CAAC,cAAc;KAC/C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config-mapping.js","sourceRoot":"","sources":["../../../src/dsl/engine-client/config-mapping.ts"],"names":[],"mappings":"AAGA,oDAAoD;AACpD,MAAM,UAAU,sBAAsB,CACpC,KAAgB;IAEhB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,OAAO,EAAE,CAAC,CAAC,SAAS;KACrB,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,GAA8B;IAC3D,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,SAA4B;IAClD,OAAO,CACL,SAAS,CAAC,gBAAgB,IAAI,CAAC;QAC/B,OAAO,SAAS,CAAC,cAAc,KAAK,QAAQ;QAC5C,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,cAAc,CAAC;QACzC,SAAS,CAAC,cAAc,GAAG,CAAC,CAC7B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,8BAA8B,CAAC,SAA4B;IASzE,OAAO;QACL,gBAAgB,EAAE,SAAS,CAAC,gBAAgB;QAC5C,cAAc,EAAE,SAAS,CAAC,cAAc;QACxC,cAAc,EAAE,SAAS,CAAC,cAAc;QACxC,YAAY,EAAE,SAAS,CAAC,YAAY;QACpC,SAAS,EAAE,cAAc,CAAC,SAAS,CAAC,eAAe,CAAC;QACpD,oBAAoB,EAAE,SAAS,CAAC,cAAc;QAC9C,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAC;AACJ,CAAC"}
@@ -2,7 +2,7 @@
2
2
  "id": "runtime",
3
3
  "name": "Senpi Runtime",
4
4
  "description": "Senpi runtime plugin for OpenClaw. Orchestrates scanners, LLM-based trade decisions, and a DSL trailing stop-loss exit engine.",
5
- "version": "3.0.171",
5
+ "version": "3.0.173",
6
6
  "commandAliases": [
7
7
  {
8
8
  "name": "senpi"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@senpi/runtime",
3
- "version": "3.0.171",
3
+ "version": "3.0.173",
4
4
  "description": "Senpi runtime plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",