@senpi/runtime 3.0.0-dev.runtime-phase-2.20260623210537 → 3.0.0-dev.runtime-phase-2.20260625112547

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.
Files changed (214) hide show
  1. package/README.md +10 -9
  2. package/dist/actions/action-runtime-module.d.ts.map +1 -1
  3. package/dist/actions/action-runtime-module.js +1 -1
  4. package/dist/actions/action-runtime-module.js.map +1 -1
  5. package/dist/actions/decision-engine.d.ts.map +1 -1
  6. package/dist/actions/decision-engine.js +3 -0
  7. package/dist/actions/decision-engine.js.map +1 -1
  8. package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
  9. package/dist/actions/open-position/open-position.action.js +54 -14
  10. package/dist/actions/open-position/open-position.action.js.map +1 -1
  11. package/dist/actions/types.d.ts +10 -2
  12. package/dist/actions/types.d.ts.map +1 -1
  13. package/dist/actions/types.js +8 -0
  14. package/dist/actions/types.js.map +1 -1
  15. package/dist/cli/guide-commands.d.ts.map +1 -1
  16. package/dist/cli/guide-commands.js +80 -74
  17. package/dist/cli/guide-commands.js.map +1 -1
  18. package/dist/cli/senpi-commands.d.ts.map +1 -1
  19. package/dist/cli/senpi-commands.js +0 -108
  20. package/dist/cli/senpi-commands.js.map +1 -1
  21. package/dist/constants/dsl/index.d.ts +2 -0
  22. package/dist/constants/dsl/index.d.ts.map +1 -1
  23. package/dist/constants/dsl/index.js +2 -0
  24. package/dist/constants/dsl/index.js.map +1 -1
  25. package/dist/dsl/config/parse-tiers.d.ts.map +1 -1
  26. package/dist/dsl/config/parse-tiers.js +6 -2
  27. package/dist/dsl/config/parse-tiers.js.map +1 -1
  28. package/dist/dsl/engine-client/config-mapping.d.ts +7 -0
  29. package/dist/dsl/engine-client/config-mapping.d.ts.map +1 -1
  30. package/dist/dsl/engine-client/config-mapping.js +16 -2
  31. package/dist/dsl/engine-client/config-mapping.js.map +1 -1
  32. package/dist/dsl/events/handlers.d.ts +18 -2
  33. package/dist/dsl/events/handlers.d.ts.map +1 -1
  34. package/dist/dsl/events/handlers.js +302 -213
  35. package/dist/dsl/events/handlers.js.map +1 -1
  36. package/dist/dsl/monitor/create-monitor.d.ts +15 -0
  37. package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
  38. package/dist/dsl/monitor/create-monitor.js +46 -9
  39. package/dist/dsl/monitor/create-monitor.js.map +1 -1
  40. package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
  41. package/dist/dsl/monitor/process-one-position.js +138 -77
  42. package/dist/dsl/monitor/process-one-position.js.map +1 -1
  43. package/dist/dsl/plugin/index.d.ts +16 -1
  44. package/dist/dsl/plugin/index.d.ts.map +1 -1
  45. package/dist/dsl/plugin/index.js +35 -4
  46. package/dist/dsl/plugin/index.js.map +1 -1
  47. package/dist/dsl/plugin/options.d.ts +18 -0
  48. package/dist/dsl/plugin/options.d.ts.map +1 -1
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +4 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/runtime/create-scanner-module.d.ts +4 -3
  53. package/dist/runtime/create-scanner-module.d.ts.map +1 -1
  54. package/dist/runtime/create-scanner-module.js +14 -5
  55. package/dist/runtime/create-scanner-module.js.map +1 -1
  56. package/dist/runtime/create-scanner-providers-for-run.d.ts.map +1 -1
  57. package/dist/runtime/create-scanner-providers-for-run.js +12 -1
  58. package/dist/runtime/create-scanner-providers-for-run.js.map +1 -1
  59. package/dist/runtime/load-runtime-config.js +1 -1
  60. package/dist/runtime/load-runtime-config.js.map +1 -1
  61. package/dist/runtime/map-strategies-registration.js +7 -8
  62. package/dist/runtime/map-strategies-registration.js.map +1 -1
  63. package/dist/runtime/map-strategies.d.ts.map +1 -1
  64. package/dist/runtime/map-strategies.js +12 -3
  65. package/dist/runtime/map-strategies.js.map +1 -1
  66. package/dist/runtime/reconcile-decide.d.ts +73 -0
  67. package/dist/runtime/reconcile-decide.d.ts.map +1 -0
  68. package/dist/runtime/reconcile-decide.js +186 -0
  69. package/dist/runtime/reconcile-decide.js.map +1 -0
  70. package/dist/runtime/reconcile-run.d.ts +62 -0
  71. package/dist/runtime/reconcile-run.d.ts.map +1 -0
  72. package/dist/runtime/reconcile-run.js +173 -0
  73. package/dist/runtime/reconcile-run.js.map +1 -0
  74. package/dist/runtime/reconcile-state.d.ts +44 -0
  75. package/dist/runtime/reconcile-state.d.ts.map +1 -1
  76. package/dist/runtime/reconcile-state.js +80 -44
  77. package/dist/runtime/reconcile-state.js.map +1 -1
  78. package/dist/runtime/risk-guard.d.ts.map +1 -1
  79. package/dist/runtime/risk-guard.js +17 -12
  80. package/dist/runtime/risk-guard.js.map +1 -1
  81. package/dist/runtime/runtime-schema.d.ts +2912 -1052
  82. package/dist/runtime/runtime-schema.d.ts.map +1 -1
  83. package/dist/runtime/runtime-schema.js +136 -42
  84. package/dist/runtime/runtime-schema.js.map +1 -1
  85. package/dist/runtime/runtime.d.ts +26 -0
  86. package/dist/runtime/runtime.d.ts.map +1 -1
  87. package/dist/runtime/runtime.js +254 -8
  88. package/dist/runtime/runtime.js.map +1 -1
  89. package/dist/runtime/scanner-registry.d.ts +1 -1
  90. package/dist/runtime/scanner-registry.d.ts.map +1 -1
  91. package/dist/runtime/scanner-registry.js +3 -12
  92. package/dist/runtime/scanner-registry.js.map +1 -1
  93. package/dist/runtime/supervisor/long-running-supervisor.d.ts.map +1 -1
  94. package/dist/runtime/supervisor/long-running-supervisor.js +1 -1
  95. package/dist/runtime/supervisor/long-running-supervisor.js.map +1 -1
  96. package/dist/runtime/supervisor/orphan-sweep.js +1 -1
  97. package/dist/runtime/supervisor/orphan-sweep.js.map +1 -1
  98. package/dist/runtime/supervisor/supervisor-utils.d.ts +1 -1
  99. package/dist/runtime/supervisor/supervisor-utils.d.ts.map +1 -1
  100. package/dist/runtime/supervisor/supervisor-utils.js +1 -1
  101. package/dist/runtime/supervisor/supervisor-utils.js.map +1 -1
  102. package/dist/runtime-api/intake/acceptance-record.d.ts +10 -0
  103. package/dist/runtime-api/intake/acceptance-record.d.ts.map +1 -1
  104. package/dist/runtime-api/intake/acceptance-record.js +28 -0
  105. package/dist/runtime-api/intake/acceptance-record.js.map +1 -1
  106. package/dist/runtime-api/intake/intake-mount.d.ts.map +1 -1
  107. package/dist/runtime-api/intake/intake-mount.js +28 -36
  108. package/dist/runtime-api/intake/intake-mount.js.map +1 -1
  109. package/dist/runtime-api/intake/process-signal-post.d.ts +20 -1
  110. package/dist/runtime-api/intake/process-signal-post.d.ts.map +1 -1
  111. package/dist/runtime-api/intake/process-signal-post.js +57 -6
  112. package/dist/runtime-api/intake/process-signal-post.js.map +1 -1
  113. package/dist/runtime-api/intake/scanner-launcher.d.ts +18 -4
  114. package/dist/runtime-api/intake/scanner-launcher.d.ts.map +1 -1
  115. package/dist/runtime-api/intake/scanner-launcher.js +24 -3
  116. package/dist/runtime-api/intake/scanner-launcher.js.map +1 -1
  117. package/dist/runtime-api/intake/types.d.ts +16 -0
  118. package/dist/runtime-api/intake/types.d.ts.map +1 -1
  119. package/dist/runtime-api/routes/signals.schema.d.ts +4 -0
  120. package/dist/runtime-api/routes/signals.schema.d.ts.map +1 -1
  121. package/dist/runtime-api/routes/signals.schema.js +12 -0
  122. package/dist/runtime-api/routes/signals.schema.js.map +1 -1
  123. package/dist/scanners/external/scaffold/__main__.py +65 -24
  124. package/dist/scanners/external/scaffold/ctx.py +78 -0
  125. package/dist/scanners/external/scaffold/delivery.py +56 -22
  126. package/dist/scanners/external/scaffold/entrypoint_loader.py +42 -48
  127. package/dist/scanners/external/scaffold/journal.py +13 -2
  128. package/dist/scanners/external/scaffold/requirements.txt +11 -0
  129. package/dist/scanners/external/scaffold/scaffold.py +159 -128
  130. package/dist/scanners/external/scaffold/senpi_mcp.py +250 -0
  131. package/dist/scanners/external/scaffold/signal_envelope.py +177 -34
  132. package/dist/scanners/external/scaffold/state_manager.py +175 -0
  133. package/dist/scanners/external-scanner-receiver.d.ts +6 -0
  134. package/dist/scanners/external-scanner-receiver.d.ts.map +1 -1
  135. package/dist/scanners/external-scanner-receiver.js +14 -1
  136. package/dist/scanners/external-scanner-receiver.js.map +1 -1
  137. package/dist/scripts/run-dsl-standalone-live.d.ts +1 -1
  138. package/dist/scripts/run-dsl-standalone-live.js +5 -3
  139. package/dist/scripts/run-dsl-standalone-live.js.map +1 -1
  140. package/dist/senpi/client.d.ts +37 -4
  141. package/dist/senpi/client.d.ts.map +1 -1
  142. package/dist/senpi/client.js +101 -24
  143. package/dist/senpi/client.js.map +1 -1
  144. package/dist/state/state-manager.d.ts +17 -0
  145. package/dist/state/state-manager.d.ts.map +1 -1
  146. package/dist/state/state-manager.js +50 -4
  147. package/dist/state/state-manager.js.map +1 -1
  148. package/dist/strategy/strategy-state.d.ts +9 -1
  149. package/dist/strategy/strategy-state.d.ts.map +1 -1
  150. package/dist/strategy/strategy-state.js +62 -9
  151. package/dist/strategy/strategy-state.js.map +1 -1
  152. package/dist/tracking/constants.d.ts.map +1 -1
  153. package/dist/tracking/constants.js +2 -0
  154. package/dist/tracking/constants.js.map +1 -1
  155. package/dist/types/dsl/index.d.ts +1 -1
  156. package/dist/types/dsl/index.d.ts.map +1 -1
  157. package/dist/types/scanner.d.ts +7 -0
  158. package/dist/types/scanner.d.ts.map +1 -1
  159. package/dist/types/strategy.d.ts +3 -1
  160. package/dist/types/strategy.d.ts.map +1 -1
  161. package/dist/utils/keyed-mutex.d.ts +37 -0
  162. package/dist/utils/keyed-mutex.d.ts.map +1 -0
  163. package/dist/utils/keyed-mutex.js +77 -0
  164. package/dist/utils/keyed-mutex.js.map +1 -0
  165. package/examples/strategies/README.md +17 -12
  166. package/examples/strategies/iguana/README.md +135 -0
  167. package/examples/strategies/iguana/recipe.yaml +137 -0
  168. package/examples/strategies/iguana/scanners/scan.py +243 -0
  169. package/examples/strategies/iguana/scanners/scoring.py +152 -0
  170. package/examples/strategies/raptor/README.md +156 -0
  171. package/examples/strategies/raptor/recipe.yaml +154 -0
  172. package/examples/strategies/raptor/scanners/scan.py +349 -0
  173. package/examples/strategies/raptor/scanners/scoring.py +452 -0
  174. package/examples/strategies/spider/README.md +89 -0
  175. package/examples/strategies/spider/scalp/recipe.yaml +129 -0
  176. package/examples/strategies/spider/scalp/scanners/scan.py +219 -0
  177. package/examples/strategies/spider/scalp/scanners/scoring.py +179 -0
  178. package/examples/strategies/spider/swing/recipe.yaml +137 -0
  179. package/examples/strategies/spider/swing/scanners/scan.py +334 -0
  180. package/examples/strategies/spider/swing/scanners/scoring.py +184 -0
  181. package/examples/strategies/turbine/README.md +166 -0
  182. package/examples/strategies/turbine/recipe-runners.yaml +123 -0
  183. package/examples/strategies/turbine/recipe-volume.yaml +129 -0
  184. package/examples/strategies/turbine/scanners/scan.py +283 -0
  185. package/examples/strategies/turbine/scanners/scoring.py +190 -0
  186. package/package.json +1 -1
  187. package/dist/scanners/external/liquidation-watchdog/README.md +0 -107
  188. package/dist/scanners/external/liquidation-watchdog/liquidation-watchdog.yaml +0 -48
  189. package/dist/scanners/external/liquidation-watchdog/producer.mjs +0 -336
  190. package/dist/scanners/external/momentum/README.md +0 -148
  191. package/dist/scanners/external/momentum/momentum.yaml +0 -116
  192. package/dist/scanners/external/momentum/producer.mjs +0 -251
  193. package/dist/scanners/external/shared/ingest.mjs +0 -112
  194. package/examples/README.md +0 -89
  195. package/examples/scanners-consumer-quickstart.mjs +0 -134
  196. package/examples/scanners-emerging-movers-v4.mjs +0 -287
  197. package/examples/scanners-liquidation-watchdog.mjs +0 -341
  198. package/examples/scanners-live-mcp.mjs +0 -208
  199. package/examples/scanners-multi-strategy.mjs +0 -165
  200. package/examples/scanners-position-tracker-e2e.mjs +0 -225
  201. package/examples/scanners-scheduled-events.mjs +0 -96
  202. package/examples/scanners-senpi-provider-client.mjs +0 -182
  203. package/examples/scanners-single-strategy.mjs +0 -198
  204. package/examples/strategies/dsl-showcase.yaml +0 -68
  205. package/examples/strategies/dsl.yaml +0 -51
  206. package/examples/strategies/fox-minimal-loosened.yaml +0 -240
  207. package/examples/strategies/fox-minimal.yaml +0 -242
  208. package/examples/strategies/minimal.yaml +0 -46
  209. package/examples/strategies/momentum/how-it-works.md +0 -48
  210. package/examples/strategies/momentum/momentum-guarded.yaml +0 -161
  211. package/examples/strategies/risk-showcase.yaml +0 -93
  212. package/examples/strategies/viper.yaml +0 -67
  213. package/examples/strategies/wolf.yaml +0 -72
  214. package/examples/yamls/sample-with-dsl-and-emerging-movers.yaml +0 -123
@@ -1,165 +0,0 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import {
5
- createScannerRuntimeModule,
6
- momentumScanner,
7
- prescreenerScanner,
8
- } from "../dist/scanners/index.js";
9
-
10
- function createInstruments() {
11
- return [
12
- {
13
- name: "BTC",
14
- isDelisted: false,
15
- maxLeverage: 10,
16
- context: {
17
- markPx: 104,
18
- prevDayPx: 100,
19
- midPx: 104,
20
- dayNtlVlm: 70_000_000,
21
- openInterest: 2_000_000_000,
22
- funding: 0.001,
23
- },
24
- },
25
- {
26
- name: "ETH",
27
- isDelisted: false,
28
- maxLeverage: 8,
29
- context: {
30
- markPx: 102.5,
31
- prevDayPx: 100,
32
- midPx: 102.5,
33
- dayNtlVlm: 50_000_000,
34
- openInterest: 1_200_000_000,
35
- funding: 0.001,
36
- },
37
- },
38
- ];
39
- }
40
-
41
- function createCandles() {
42
- return {
43
- BTC: {
44
- candles: {
45
- "1h": [
46
- {
47
- timestamp: 1,
48
- open: 100,
49
- high: 102,
50
- low: 99,
51
- close: 100,
52
- volume: 1200,
53
- },
54
- {
55
- timestamp: 2,
56
- open: 100,
57
- high: 105,
58
- low: 100,
59
- close: 104,
60
- volume: 1400,
61
- },
62
- ],
63
- },
64
- },
65
- ETH: {
66
- candles: {
67
- "1h": [
68
- {
69
- timestamp: 1,
70
- open: 100,
71
- high: 101,
72
- low: 99,
73
- close: 100,
74
- volume: 900,
75
- },
76
- {
77
- timestamp: 2,
78
- open: 100,
79
- high: 103,
80
- low: 100,
81
- close: 102.5,
82
- volume: 1100,
83
- },
84
- ],
85
- },
86
- },
87
- };
88
- }
89
-
90
- async function main() {
91
- const stateDir = await mkdtemp(join(tmpdir(), "scanners-example-multi-"));
92
-
93
- const module = createScannerRuntimeModule({
94
- stateDir,
95
- scanners: [prescreenerScanner, momentumScanner],
96
- strategies: [
97
- {
98
- id: "alpha",
99
- name: "Alpha",
100
- scannerOverrides: {
101
- momentum: {
102
- config: {
103
- timeframe: "1h",
104
- minMovePct: 3.5,
105
- maxCandidates: 10,
106
- minDayVolume: 1_000_000,
107
- minSignalScore: 0.2,
108
- requirePrescreened: true,
109
- },
110
- },
111
- },
112
- },
113
- {
114
- id: "beta",
115
- name: "Beta",
116
- scannerOverrides: {
117
- momentum: {
118
- config: {
119
- timeframe: "1h",
120
- minMovePct: 1.5,
121
- maxCandidates: 10,
122
- minDayVolume: 1_000_000,
123
- minSignalScore: 0.2,
124
- requirePrescreened: true,
125
- },
126
- },
127
- },
128
- },
129
- ],
130
- providers: {
131
- getInstruments: async () => createInstruments(),
132
- getCandles: async () => createCandles(),
133
- },
134
- });
135
-
136
- try {
137
- await module.runOnce("alpha", "prescreener");
138
- await module.runOnce("beta", "prescreener");
139
-
140
- const alphaMomentum = await module.runOnce("alpha", "momentum");
141
- const betaMomentum = await module.runOnce("beta", "momentum");
142
-
143
- const alphaSignals = await module.querySignals({
144
- strategyId: "alpha",
145
- scannerId: "momentum",
146
- });
147
- const betaSignals = await module.querySignals({
148
- strategyId: "beta",
149
- scannerId: "momentum",
150
- });
151
-
152
- console.log("multi-strategy: alpha momentum signals =", alphaMomentum.signals.length);
153
- console.log("multi-strategy: beta momentum signals =", betaMomentum.signals.length);
154
- console.log("multi-strategy: alpha queried signals =", alphaSignals.length);
155
- console.log("multi-strategy: beta queried signals =", betaSignals.length);
156
- } finally {
157
- await module.stop();
158
- await rm(stateDir, { recursive: true, force: true });
159
- }
160
- }
161
-
162
- main().catch((error) => {
163
- console.error(error);
164
- process.exit(1);
165
- });
@@ -1,225 +0,0 @@
1
- /**
2
- * Position-tracker E2E example — connects to the real Senpi MCP server,
3
- * fetches clearing house state for a strategy wallet, and runs the
4
- * position-tracker scanner to detect open positions and deltas.
5
- *
6
- * Runs 3 iterations to showcase the full lifecycle:
7
- * 1. First run — all current positions appear as POSITION_OPENED deltas.
8
- * 2. Second run — no deltas (positions unchanged between scans).
9
- * 3. Third run — same as second (steady-state heartbeat).
10
- *
11
- * Requires environment variables:
12
- *
13
- * export SENPI_API_KEY="your-api-key"
14
- * export SENPI_MCP_URL="https://mcp.prod.senpi.ai/mcp"
15
- *
16
- * Optionally set STRATEGY_ADDRESS to override the default wallet:
17
- *
18
- * export STRATEGY_ADDRESS="0x..."
19
- *
20
- * Usage:
21
- *
22
- * npm run build
23
- * node examples/scanners-position-tracker-e2e.mjs
24
- */
25
-
26
- import { mkdtemp, rm } from "node:fs/promises";
27
- import { tmpdir } from "node:os";
28
- import { join } from "node:path";
29
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
30
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
31
- import {
32
- createScannerRuntimeModule,
33
- createSenpiScannerProviders,
34
- positionTrackerScanner,
35
- } from "../dist/scanners/index.js";
36
-
37
- // ─── Env guard ──────────────────────────────────────────────────────────────
38
-
39
- const SENPI_API_KEY = process.env.SENPI_API_KEY;
40
- const SENPI_MCP_URL = process.env.SENPI_MCP_URL;
41
- const STRATEGY_ADDRESS =
42
- process.env.STRATEGY_ADDRESS;
43
-
44
- if (!SENPI_API_KEY || !SENPI_MCP_URL || !STRATEGY_ADDRESS) {
45
- console.error(
46
- "Missing required env vars. Set SENPI_API_KEY, SENPI_MCP_URL, and STRATEGY_ADDRESS before running.\n" +
47
- " export SENPI_API_KEY='your-api-key'\n" +
48
- " export SENPI_MCP_URL='https://mcp.prod.senpi.ai/mcp'\n" +
49
- " export STRATEGY_ADDRESS='0x...'",
50
- );
51
- process.exit(1);
52
- }
53
-
54
- // ─── MCP → SenpiToolClient bridge ──────────────────────────────────────────
55
-
56
- function createSenpiToolClient(mcpClient) {
57
- return {
58
- async callTool(name, args) {
59
- const result = await mcpClient.callTool({ name, arguments: args });
60
-
61
- if (result.isError) {
62
- const errorText =
63
- Array.isArray(result.content) &&
64
- result.content.length > 0 &&
65
- result.content[0].type === "text"
66
- ? result.content[0].text
67
- : JSON.stringify(result.content);
68
- throw new Error(`MCP tool "${name}" returned error: ${errorText}`);
69
- }
70
-
71
- if (result.structuredContent !== undefined) {
72
- return result.structuredContent;
73
- }
74
-
75
- if (Array.isArray(result.content) && result.content.length > 0) {
76
- const first = result.content[0];
77
- if (first.type === "text") {
78
- try {
79
- return JSON.parse(first.text);
80
- } catch {
81
- return first.text;
82
- }
83
- }
84
- }
85
-
86
- return result.content;
87
- },
88
- };
89
- }
90
-
91
- // ─── Helpers ────────────────────────────────────────────────────────────────
92
-
93
- function printPositionSnapshot(snapshot, indent = " ") {
94
- console.log(
95
- `${indent}${snapshot.direction} ${snapshot.asset} on ${snapshot.dex}`,
96
- );
97
- console.log(
98
- `${indent} size: ${snapshot.size} entry: $${snapshot.entryPrice} leverage: ${snapshot.leverage}x (${snapshot.leverageType})`,
99
- );
100
- console.log(
101
- `${indent} margin: $${snapshot.margin.toFixed(2)} liqPrice: ${snapshot.liquidationPrice != null ? "$" + snapshot.liquidationPrice.toFixed(2) : "n/a"}`,
102
- );
103
- console.log(
104
- `${indent} uPnL: $${snapshot.unrealizedPnl.toFixed(4)} ROE: ${snapshot.roe.toFixed(2)}%`,
105
- );
106
- }
107
-
108
- function printDelta(signal) {
109
- const meta = signal.meta || {};
110
- console.log(
111
- ` [${signal.signalType}] ${meta.positionKey} sizeDelta=${meta.sizeDelta}`,
112
- );
113
- if (meta.current) {
114
- printPositionSnapshot(meta.current);
115
- }
116
- }
117
-
118
- // ─── Main ───────────────────────────────────────────────────────────────────
119
-
120
- async function main() {
121
- // 1. Connect to MCP.
122
- console.log("Connecting to", SENPI_MCP_URL, "...");
123
- const transport = new StreamableHTTPClientTransport(new URL(SENPI_MCP_URL), {
124
- requestInit: {
125
- headers: { Authorization: `Bearer ${SENPI_API_KEY}` },
126
- },
127
- });
128
- const mcpClient = new Client({
129
- name: "position-tracker-e2e",
130
- version: "0.0.1",
131
- });
132
- await mcpClient.connect(transport);
133
- console.log("Connected.\n");
134
-
135
- // 2. Create providers backed by the real MCP client.
136
- const providers = createSenpiScannerProviders({
137
- client: createSenpiToolClient(mcpClient),
138
- logLevel: "warn",
139
- cacheTtlMs: { instruments: 0, smData: 0, candles: 0 },
140
- retries: 2,
141
- });
142
-
143
- // 3. Create the scanner runtime module with position-tracker only.
144
- const stateDir = await mkdtemp(join(tmpdir(), "position-tracker-e2e-"));
145
- const mod = createScannerRuntimeModule({
146
- stateDir,
147
- scanners: [positionTrackerScanner],
148
- strategies: [{ id: STRATEGY_ADDRESS, name: "E2E Position Tracker" }],
149
- providers,
150
- });
151
-
152
- try {
153
- console.log(`Strategy address: ${STRATEGY_ADDRESS}\n`);
154
-
155
- // ── Run 1: first scan — all positions appear as POSITION_OPENED ─────
156
- console.log("── Run 1 (initial scan) ──");
157
- const run1 = await mod.runOnce(STRATEGY_ADDRESS, "position-tracker");
158
- console.log(" status:", run1.status);
159
- console.log(" positionCount:", run1.summary?.positionCount ?? 0);
160
- console.log(" deltaCount:", run1.summary?.deltaCount ?? 0);
161
- console.log(" signals:", run1.signals.length);
162
- if (run1.signals.length > 0) {
163
- console.log("\n Deltas:");
164
- for (const sig of run1.signals) {
165
- printDelta(sig);
166
- }
167
- }
168
- console.log();
169
-
170
- // ── Run 2: second scan — should be steady state (no deltas) ─────────
171
- console.log("── Run 2 (steady state) ──");
172
- const run2 = await mod.runOnce(STRATEGY_ADDRESS, "position-tracker");
173
- console.log(" status:", run2.status);
174
- console.log(" positionCount:", run2.summary?.positionCount ?? 0);
175
- console.log(" deltaCount:", run2.summary?.deltaCount ?? 0);
176
- console.log(" signals:", run2.signals.length);
177
- if (run2.signals.length > 0) {
178
- console.log("\n Unexpected deltas:");
179
- for (const sig of run2.signals) {
180
- printDelta(sig);
181
- }
182
- } else {
183
- console.log(" (no deltas — positions unchanged, as expected)");
184
- }
185
- console.log();
186
-
187
- // ── Run 3: third scan — still steady state ──────────────────────────
188
- console.log("── Run 3 (steady state) ──");
189
- const run3 = await mod.runOnce(STRATEGY_ADDRESS, "position-tracker");
190
- console.log(" status:", run3.status);
191
- console.log(" positionCount:", run3.summary?.positionCount ?? 0);
192
- console.log(" deltaCount:", run3.summary?.deltaCount ?? 0);
193
- console.log(" signals:", run3.signals.length);
194
- if (run3.signals.length > 0) {
195
- console.log("\n Unexpected deltas:");
196
- for (const sig of run3.signals) {
197
- printDelta(sig);
198
- }
199
- } else {
200
- console.log(" (no deltas — positions unchanged, as expected)");
201
- }
202
- console.log();
203
-
204
- // ── Query all persisted signals ─────────────────────────────────────
205
- const allSignals = await mod.querySignals({
206
- strategyId: STRATEGY_ADDRESS,
207
- });
208
- console.log("── Persisted signals ──");
209
- console.log(" total:", allSignals.length);
210
- for (const sig of allSignals) {
211
- console.log(
212
- ` [${sig.scannerId}] ${sig.signalType} ${sig.asset} (${sig.direction})`,
213
- );
214
- }
215
- } finally {
216
- await mod.stop();
217
- await transport.close();
218
- await rm(stateDir, { recursive: true, force: true });
219
- }
220
- }
221
-
222
- main().catch((error) => {
223
- console.error(error);
224
- process.exit(1);
225
- });
@@ -1,96 +0,0 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import {
5
- createScannerRuntimeModule,
6
- buildCompositionFromScanners,
7
- oiTrackerScanner,
8
- } from "../dist/scanners/index.js";
9
-
10
- function createInstruments() {
11
- return [
12
- {
13
- name: "BTC",
14
- isDelisted: false,
15
- maxLeverage: 10,
16
- context: {
17
- markPx: 100,
18
- prevDayPx: 99,
19
- midPx: 100,
20
- dayNtlVlm: 60_000_000,
21
- openInterest: 2_200_000_000,
22
- funding: 0.001,
23
- },
24
- },
25
- ];
26
- }
27
-
28
- function sleep(ms) {
29
- return new Promise((resolve) => setTimeout(resolve, ms));
30
- }
31
-
32
- async function main() {
33
- const stateDir = await mkdtemp(join(tmpdir(), "scanners-example-scheduled-"));
34
- const events = {
35
- start: 0,
36
- complete: 0,
37
- skip: 0,
38
- error: 0,
39
- };
40
-
41
- const module = createScannerRuntimeModule({
42
- stateDir,
43
- ...buildCompositionFromScanners([oiTrackerScanner]),
44
- strategies: [
45
- {
46
- id: "alpha",
47
- name: "Alpha",
48
- scannerOverrides: {
49
- "oi-tracker": {
50
- intervalSeconds: 1,
51
- config: {
52
- minDayVolume: 1_000_000,
53
- maxHistory: 5,
54
- },
55
- },
56
- },
57
- },
58
- ],
59
- providers: {
60
- getInstruments: async () => createInstruments(),
61
- },
62
- });
63
-
64
- module.on("scanner:run:start", () => {
65
- events.start += 1;
66
- });
67
- module.on("scanner:run:complete", () => {
68
- events.complete += 1;
69
- });
70
- module.on("scanner:run:skip", () => {
71
- events.skip += 1;
72
- });
73
- module.on("scanner:run:error", () => {
74
- events.error += 1;
75
- });
76
-
77
- try {
78
- await module.start();
79
- await sleep(2200);
80
- await module.stop();
81
- await sleep(100);
82
-
83
- console.log("scheduled-events: start =", events.start);
84
- console.log("scheduled-events: complete =", events.complete);
85
- console.log("scheduled-events: skip =", events.skip);
86
- console.log("scheduled-events: error =", events.error);
87
- } finally {
88
- await module.stop();
89
- await rm(stateDir, { recursive: true, force: true });
90
- }
91
- }
92
-
93
- main().catch((error) => {
94
- console.error(error);
95
- process.exit(1);
96
- });
@@ -1,182 +0,0 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import {
5
- createScannerRuntimeModule,
6
- createSenpiScannerProviders,
7
- emergingMoversScanner,
8
- momentumScanner,
9
- prescreenerScanner,
10
- } from "../dist/scanners/index.js";
11
-
12
- function createMockSenpiToolClient() {
13
- let smRun = 0;
14
- return {
15
- async callTool(name, args) {
16
- if (name === "market_list_instruments") {
17
- return {
18
- success: true,
19
- data: {
20
- instruments: [
21
- {
22
- name: "BTC",
23
- is_delisted: false,
24
- max_leverage: 10,
25
- context: {
26
- markPx: 106,
27
- prevDayPx: 100,
28
- midPx: 106,
29
- dayNtlVlm: 80_000_000,
30
- openInterest: 2_000_000_000,
31
- funding: 0.001,
32
- },
33
- },
34
- {
35
- name: "ETH",
36
- is_delisted: false,
37
- max_leverage: 8,
38
- context: {
39
- markPx: 101,
40
- prevDayPx: 100,
41
- midPx: 101,
42
- dayNtlVlm: 40_000_000,
43
- openInterest: 1_000_000_000,
44
- funding: 0.001,
45
- },
46
- },
47
- ],
48
- },
49
- };
50
- }
51
-
52
- if (name === "market_get_asset_data") {
53
- if (args.asset === "BTC") {
54
- return {
55
- candles: {
56
- "1h": [
57
- { t: 1, o: 100, h: 102, l: 99, c: 100, v: 1000 },
58
- { t: 2, o: 100, h: 107, l: 100, c: 106, v: 1400 },
59
- ],
60
- },
61
- };
62
- }
63
- return {
64
- candles: {
65
- "1h": [
66
- { t: 1, o: 100, h: 101, l: 99, c: 100, v: 900 },
67
- { t: 2, o: 100, h: 101, l: 99, c: 100.4, v: 920 },
68
- ],
69
- },
70
- };
71
- }
72
-
73
- if (name === "leaderboard_get_markets") {
74
- smRun += 1;
75
- const run1 = [
76
- {
77
- token: "SOL",
78
- direction: "up",
79
- pct_of_top_traders_gain: 0.16,
80
- trader_count: 220,
81
- token_price_change_pct_4h: 2.1,
82
- },
83
- {
84
- token: "AVAX",
85
- direction: "up",
86
- pct_of_top_traders_gain: 0.18,
87
- trader_count: 200,
88
- token_price_change_pct_4h: 1.9,
89
- },
90
- ];
91
- const run2 = [
92
- {
93
- token: "AVAX",
94
- direction: "up",
95
- pct_of_top_traders_gain: 0.17,
96
- trader_count: 230,
97
- token_price_change_pct_4h: 2.0,
98
- },
99
- {
100
- token: "SOL",
101
- direction: "up",
102
- pct_of_top_traders_gain: 0.35,
103
- trader_count: 250,
104
- token_price_change_pct_4h: 4.2,
105
- },
106
- ];
107
- return {
108
- markets: {
109
- markets: smRun === 1 ? run1 : run2,
110
- },
111
- };
112
- }
113
-
114
- throw new Error(`Unexpected tool call: ${name}`);
115
- },
116
- };
117
- }
118
-
119
- async function main() {
120
- const stateDir = await mkdtemp(join(tmpdir(), "scanners-example-senpi-provider-"));
121
- const toolClient = createMockSenpiToolClient();
122
- const providers = createSenpiScannerProviders({
123
- client: toolClient,
124
- logLevel: "error",
125
- maxCandleAssets: 10,
126
- candleIntervals: ["1h"],
127
- cacheTtlMs: {
128
- smData: 0,
129
- },
130
- });
131
-
132
- const module = createScannerRuntimeModule({
133
- stateDir,
134
- scanners: [prescreenerScanner, momentumScanner, emergingMoversScanner],
135
- strategies: [
136
- {
137
- id: "alpha",
138
- name: "Alpha",
139
- scannerOverrides: {
140
- momentum: {
141
- config: {
142
- timeframe: "1h",
143
- minMovePct: 1.5,
144
- maxCandidates: 10,
145
- minDayVolume: 1_000_000,
146
- minSignalScore: 0.2,
147
- requirePrescreened: true,
148
- },
149
- },
150
- "emerging-movers": {
151
- config: {
152
- topN: 10,
153
- minRankJump: 1,
154
- minTopTradersGain: 0.15,
155
- minScansBeforeSignals: 2,
156
- historyLimit: 30,
157
- },
158
- },
159
- },
160
- },
161
- ],
162
- providers,
163
- });
164
-
165
- try {
166
- await module.runOnce("alpha", "prescreener");
167
- const momentum = await module.runOnce("alpha", "momentum");
168
- await module.runOnce("alpha", "emerging-movers");
169
- const emerging = await module.runOnce("alpha", "emerging-movers");
170
-
171
- console.log("senpi-provider: momentum signals =", momentum.signals.length);
172
- console.log("senpi-provider: emerging signals =", emerging.signals.length);
173
- } finally {
174
- await module.stop();
175
- await rm(stateDir, { recursive: true, force: true });
176
- }
177
- }
178
-
179
- main().catch((error) => {
180
- console.error(error);
181
- process.exit(1);
182
- });