@senpi/runtime 3.0.9-dev.20260710204324 → 3.0.9-dev.feat-strategy-compos.20260716013009

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 (94) hide show
  1. package/dist/cli/composer-commands.d.ts +37 -0
  2. package/dist/cli/composer-commands.d.ts.map +1 -0
  3. package/dist/cli/composer-commands.js +287 -0
  4. package/dist/cli/composer-commands.js.map +1 -0
  5. package/dist/cli/senpi-commands.d.ts.map +1 -1
  6. package/dist/cli/senpi-commands.js +2 -0
  7. package/dist/cli/senpi-commands.js.map +1 -1
  8. package/dist/cli/validate-runtime-config.mjs +124 -0
  9. package/dist/composer/AUTHORING.md +233 -0
  10. package/dist/composer/__init__.py +29 -0
  11. package/dist/composer/authoring/__init__.py +49 -0
  12. package/dist/composer/authoring/answers.py +226 -0
  13. package/dist/composer/authoring/archetypes/__init__.py +25 -0
  14. package/dist/composer/authoring/archetypes/_common.py +218 -0
  15. package/dist/composer/authoring/archetypes/classifier.py +109 -0
  16. package/dist/composer/authoring/archetypes/skeleton.py +54 -0
  17. package/dist/composer/authoring/archetypes/thesis_fund.py +103 -0
  18. package/dist/composer/authoring/archetypes/trend_momentum.py +104 -0
  19. package/dist/composer/authoring/builder.py +191 -0
  20. package/dist/composer/authoring/emit.py +264 -0
  21. package/dist/composer/authoring/gaps.py +115 -0
  22. package/dist/composer/authoring/generate.py +131 -0
  23. package/dist/composer/authoring/presets.py +168 -0
  24. package/dist/composer/authoring/runtime_emit.py +266 -0
  25. package/dist/composer/authoring/strategy_manifest.py +94 -0
  26. package/dist/composer/cli.py +355 -0
  27. package/dist/composer/compiler/__init__.py +22 -0
  28. package/dist/composer/compiler/compile.py +550 -0
  29. package/dist/composer/examples/breakout_swing.graph.yaml +121 -0
  30. package/dist/composer/examples/conviction_scorer.graph.yaml +216 -0
  31. package/dist/composer/examples/macro_thesis_basket.graph.yaml +247 -0
  32. package/dist/composer/examples/pre_listing_classifier.graph.yaml +204 -0
  33. package/dist/composer/examples/trend_momentum_majors.graph.yaml +133 -0
  34. package/dist/composer/generated/README.md +22 -0
  35. package/dist/composer/generated/catalog.md +84 -0
  36. package/dist/composer/generated/describe.md +703 -0
  37. package/dist/composer/generated/graph.schema.json +1203 -0
  38. package/dist/composer/primitives/__init__.py +239 -0
  39. package/dist/composer/primitives/_candles.py +76 -0
  40. package/dist/composer/primitives/adapter.py +120 -0
  41. package/dist/composer/primitives/emitters.py +142 -0
  42. package/dist/composer/primitives/filters.py +71 -0
  43. package/dist/composer/primitives/indicators.py +203 -0
  44. package/dist/composer/primitives/rankers.py +40 -0
  45. package/dist/composer/primitives/scorers.py +100 -0
  46. package/dist/composer/primitives/sources.py +405 -0
  47. package/dist/composer/primitives/stateful.py +52 -0
  48. package/dist/composer/pure_fn/__init__.py +34 -0
  49. package/dist/composer/pure_fn/checks.py +39 -0
  50. package/dist/composer/pure_fn/models.py +177 -0
  51. package/dist/composer/pure_fn/purity.py +311 -0
  52. package/dist/composer/pure_fn/runtests.py +155 -0
  53. package/dist/composer/registry/__init__.py +40 -0
  54. package/dist/composer/registry/generate.py +422 -0
  55. package/dist/composer/registry/models.py +331 -0
  56. package/dist/composer/registry/nodes.py +673 -0
  57. package/dist/composer/requirements.txt +21 -0
  58. package/dist/composer/templates/__init__.py +13 -0
  59. package/dist/composer/templates/scan.py.j2 +31 -0
  60. package/dist/composer/validator/__init__.py +29 -0
  61. package/dist/composer/validator/desugar.py +133 -0
  62. package/dist/composer/validator/errors.py +191 -0
  63. package/dist/composer/validator/graph_checks.py +348 -0
  64. package/dist/composer/validator/loader.py +110 -0
  65. package/dist/composer/validator/schema_checks.py +147 -0
  66. package/dist/composer/validator/validate.py +86 -0
  67. package/dist/composer/verbs/__init__.py +33 -0
  68. package/dist/composer/verbs/check.py +193 -0
  69. package/dist/composer/verbs/deploy.py +223 -0
  70. package/dist/composer/verbs/docs.py +30 -0
  71. package/dist/composer/verbs/runtime_validate.py +262 -0
  72. package/dist/composer/verbs/smoke.py +115 -0
  73. package/dist/composer/verbs/status.py +205 -0
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +2 -9
  76. package/dist/index.js.map +1 -1
  77. package/dist/runtime-api/config.d.ts +2 -2
  78. package/dist/runtime-api/config.js +4 -4
  79. package/dist/runtime-api/config.js.map +1 -1
  80. package/dist/runtime-api/handlers/ingest-signals.d.ts +3 -5
  81. package/dist/runtime-api/handlers/ingest-signals.d.ts.map +1 -1
  82. package/dist/runtime-api/handlers/ingest-signals.js +5 -14
  83. package/dist/runtime-api/handlers/ingest-signals.js.map +1 -1
  84. package/dist/runtime-api/intake/intake-mount.d.ts.map +1 -1
  85. package/dist/runtime-api/intake/intake-mount.js +2 -8
  86. package/dist/runtime-api/intake/intake-mount.js.map +1 -1
  87. package/dist/skills-manager/manifest.js +1 -1
  88. package/dist/skills-manager/manifest.js.map +1 -1
  89. package/dist/skills-manager/skills-manifest.json +1 -1
  90. package/package.json +4 -2
  91. package/dist/runtime-api/intake/ingest-mutex.d.ts +0 -16
  92. package/dist/runtime-api/intake/ingest-mutex.d.ts.map +0 -1
  93. package/dist/runtime-api/intake/ingest-mutex.js +0 -18
  94. package/dist/runtime-api/intake/ingest-mutex.js.map +0 -1
@@ -0,0 +1,1203 @@
1
+ {
2
+ "$defs": {
3
+ "params_acceleration": {
4
+ "additionalProperties": false,
5
+ "properties": {
6
+ "interval": {
7
+ "default": "4h",
8
+ "description": "Candle interval to read.",
9
+ "type": "string"
10
+ },
11
+ "long_window": {
12
+ "default": 6,
13
+ "description": "Long move window.",
14
+ "minimum": 2.0,
15
+ "type": "integer"
16
+ },
17
+ "short_window": {
18
+ "default": 3,
19
+ "description": "Short move window.",
20
+ "minimum": 1.0,
21
+ "type": "integer"
22
+ }
23
+ },
24
+ "type": "object"
25
+ },
26
+ "params_asset_trading_limits_fetch": {
27
+ "additionalProperties": false,
28
+ "properties": {
29
+ "dex": {
30
+ "default": "",
31
+ "description": "Venue filter (e.g. 'xyz'); empty means the default venue.",
32
+ "type": "string"
33
+ }
34
+ },
35
+ "type": "object"
36
+ },
37
+ "params_breakout_detect": {
38
+ "additionalProperties": false,
39
+ "properties": {
40
+ "interval": {
41
+ "default": "1h",
42
+ "description": "Candle interval to read.",
43
+ "type": "string"
44
+ },
45
+ "window": {
46
+ "default": 168,
47
+ "description": "Prior-close window (hawk 168h).",
48
+ "minimum": 2.0,
49
+ "type": "integer"
50
+ }
51
+ },
52
+ "type": "object"
53
+ },
54
+ "params_candles_fetch": {
55
+ "additionalProperties": false,
56
+ "properties": {
57
+ "include_asset_context": {
58
+ "default": false,
59
+ "description": "Also fetch markPx/prevDayPx asset_context (thesis-fund 24h return).",
60
+ "type": "boolean"
61
+ },
62
+ "include_funding": {
63
+ "default": false,
64
+ "description": "Also fetch funding series (bison funding-alignment).",
65
+ "type": "boolean"
66
+ },
67
+ "intervals": {
68
+ "default": [
69
+ "4h"
70
+ ],
71
+ "description": "Candle intervals to fetch (stag 4h; hawk 1h+4h; bison 15m/1h/4h).",
72
+ "items": {
73
+ "type": "string"
74
+ },
75
+ "type": "array"
76
+ },
77
+ "whitelist": {
78
+ "default": [],
79
+ "description": "Static universe used when no `assets` input is wired (stag whitelist).",
80
+ "items": {
81
+ "type": "string"
82
+ },
83
+ "type": "array"
84
+ }
85
+ },
86
+ "type": "object"
87
+ },
88
+ "params_classifier_predicate": {
89
+ "additionalProperties": false,
90
+ "properties": {
91
+ "exclude_delisted": {
92
+ "default": true,
93
+ "description": "Drop delisted instruments.",
94
+ "type": "boolean"
95
+ },
96
+ "max_funding_abs": {
97
+ "default": 1e-07,
98
+ "description": "Reject if |funding| exceeds this (magpie 1e-7).",
99
+ "minimum": 0.0,
100
+ "type": "number"
101
+ },
102
+ "max_leverage": {
103
+ "default": 5.0,
104
+ "description": "Reject if venue max leverage exceeds this (magpie <=5).",
105
+ "minimum": 1.0,
106
+ "type": "number"
107
+ }
108
+ },
109
+ "type": "object"
110
+ },
111
+ "params_clearinghouse_state": {
112
+ "additionalProperties": false,
113
+ "properties": {},
114
+ "type": "object"
115
+ },
116
+ "params_emit_single_best": {
117
+ "additionalProperties": false,
118
+ "properties": {
119
+ "min_score": {
120
+ "default": 0.0,
121
+ "description": "Floor below which nothing is emitted.",
122
+ "type": "number"
123
+ }
124
+ },
125
+ "type": "object"
126
+ },
127
+ "params_hard_gates_all": {
128
+ "additionalProperties": false,
129
+ "properties": {
130
+ "min_score": {
131
+ "default": 0.0,
132
+ "description": "Minimum score to keep the candidate.",
133
+ "minimum": 0.0,
134
+ "type": "number"
135
+ },
136
+ "required_gates": {
137
+ "default": [],
138
+ "description": "Feature keys that must ALL be truthy (stag's 5 gates).",
139
+ "items": {
140
+ "type": "string"
141
+ },
142
+ "type": "array"
143
+ },
144
+ "weights": {
145
+ "additionalProperties": {
146
+ "type": "number"
147
+ },
148
+ "default": {},
149
+ "description": "Feature-key -> weight for the weighted-sum score (bespoke edge slot).",
150
+ "type": "object"
151
+ }
152
+ },
153
+ "type": "object"
154
+ },
155
+ "params_held_asset_exclusion": {
156
+ "additionalProperties": false,
157
+ "properties": {},
158
+ "type": "object"
159
+ },
160
+ "params_instrument_list": {
161
+ "additionalProperties": false,
162
+ "properties": {
163
+ "dex": {
164
+ "default": "",
165
+ "description": "Venue filter (e.g. 'xyz'); empty means all venues (magpie uses 'xyz').",
166
+ "type": "string"
167
+ }
168
+ },
169
+ "type": "object"
170
+ },
171
+ "params_live_instrument_validation": {
172
+ "additionalProperties": false,
173
+ "properties": {},
174
+ "type": "object"
175
+ },
176
+ "params_market_prices_fetch": {
177
+ "additionalProperties": false,
178
+ "properties": {
179
+ "dex": {
180
+ "default": "",
181
+ "description": "Venue filter (e.g. 'xyz'); empty means the default venue.",
182
+ "type": "string"
183
+ }
184
+ },
185
+ "type": "object"
186
+ },
187
+ "params_open_orders_fetch": {
188
+ "additionalProperties": false,
189
+ "properties": {},
190
+ "type": "object"
191
+ },
192
+ "params_own_return_24h": {
193
+ "additionalProperties": false,
194
+ "properties": {},
195
+ "type": "object"
196
+ },
197
+ "params_pct_change": {
198
+ "additionalProperties": false,
199
+ "properties": {
200
+ "interval": {
201
+ "default": "4h",
202
+ "description": "Candle interval to read.",
203
+ "type": "string"
204
+ },
205
+ "lookback": {
206
+ "default": 42,
207
+ "description": "Bars to look back (stag 7d ~= 42 x 4h).",
208
+ "minimum": 1.0,
209
+ "type": "integer"
210
+ }
211
+ },
212
+ "type": "object"
213
+ },
214
+ "params_rank_pool_cap_to_open_slots": {
215
+ "additionalProperties": false,
216
+ "properties": {
217
+ "max_slots": {
218
+ "default": 5,
219
+ "description": "Maximum concurrent positions.",
220
+ "maximum": 50.0,
221
+ "minimum": 1.0,
222
+ "type": "integer"
223
+ },
224
+ "min_score": {
225
+ "default": 0.0,
226
+ "description": "Floor below which a candidate is dropped.",
227
+ "type": "number"
228
+ }
229
+ },
230
+ "type": "object"
231
+ },
232
+ "params_recent_high_bars_ago": {
233
+ "additionalProperties": false,
234
+ "properties": {
235
+ "interval": {
236
+ "default": "4h",
237
+ "description": "Candle interval to read.",
238
+ "type": "string"
239
+ },
240
+ "window": {
241
+ "default": 60,
242
+ "description": "Bars in the high-water window.",
243
+ "minimum": 2.0,
244
+ "type": "integer"
245
+ }
246
+ },
247
+ "type": "object"
248
+ },
249
+ "params_recent_signal_ttl_dedup": {
250
+ "additionalProperties": false,
251
+ "properties": {},
252
+ "type": "object"
253
+ },
254
+ "params_rsi": {
255
+ "additionalProperties": false,
256
+ "properties": {
257
+ "interval": {
258
+ "default": "1h",
259
+ "description": "Candle interval to read.",
260
+ "type": "string"
261
+ },
262
+ "period": {
263
+ "default": 14,
264
+ "description": "RSI lookback (default 14).",
265
+ "maximum": 100.0,
266
+ "minimum": 2.0,
267
+ "type": "integer"
268
+ }
269
+ },
270
+ "type": "object"
271
+ },
272
+ "params_signal_envelope": {
273
+ "additionalProperties": false,
274
+ "properties": {
275
+ "clamp_leverage_to_venue": {
276
+ "default": true,
277
+ "description": "Clamp leverage down to the instrument's venue max (magpie/thesis-fund).",
278
+ "type": "boolean"
279
+ },
280
+ "leverage": {
281
+ "default": 3.0,
282
+ "description": "Requested leverage before any venue clamp.",
283
+ "maximum": 50.0,
284
+ "minimum": 1.0,
285
+ "type": "number"
286
+ },
287
+ "margin_pct": {
288
+ "default": 5.0,
289
+ "description": "Percent of withdrawable to allocate, (0,100] (never a fraction or USD).",
290
+ "maximum": 100.0,
291
+ "minimum": 0.0001,
292
+ "type": "number"
293
+ },
294
+ "signal_type": {
295
+ "default": "",
296
+ "description": "Optional signal_type label carried on every emitted signal ('' = none).",
297
+ "type": "string"
298
+ },
299
+ "valid_for_seconds": {
300
+ "default": 0,
301
+ "description": "Per-signal TTL override in seconds; 0 = inherit the runtime default TTL.",
302
+ "minimum": 0.0,
303
+ "type": "integer"
304
+ }
305
+ },
306
+ "type": "object"
307
+ },
308
+ "params_sm_lean": {
309
+ "additionalProperties": false,
310
+ "properties": {
311
+ "agree_threshold": {
312
+ "default": 0.55,
313
+ "description": "Fraction of aligned SM required to count as agreeing (corpus 0.55-0.60).",
314
+ "maximum": 1.0,
315
+ "minimum": 0.0,
316
+ "type": "number"
317
+ }
318
+ },
319
+ "type": "object"
320
+ },
321
+ "params_sma": {
322
+ "additionalProperties": false,
323
+ "properties": {
324
+ "interval": {
325
+ "default": "4h",
326
+ "description": "Candle interval to read.",
327
+ "type": "string"
328
+ },
329
+ "period": {
330
+ "default": 200,
331
+ "description": "Lookback in bars (stag uses 200).",
332
+ "maximum": 1000.0,
333
+ "minimum": 1.0,
334
+ "type": "integer"
335
+ }
336
+ },
337
+ "type": "object"
338
+ },
339
+ "params_strategy_list_fetch": {
340
+ "additionalProperties": false,
341
+ "properties": {
342
+ "status": {
343
+ "default": "",
344
+ "description": "Filter by strategy status (e.g. 'ACTIVE'); empty means all.",
345
+ "type": "string"
346
+ },
347
+ "strategy_type": {
348
+ "default": "",
349
+ "description": "Filter by strategy type; empty means all.",
350
+ "type": "string"
351
+ }
352
+ },
353
+ "type": "object"
354
+ },
355
+ "params_strategy_pnl_snapshot": {
356
+ "additionalProperties": false,
357
+ "properties": {
358
+ "drawdown_reset_on_day_rollover": {
359
+ "default": false,
360
+ "description": "Reset drawdown at the day boundary (passed through to the MCP call).",
361
+ "type": "boolean"
362
+ },
363
+ "period": {
364
+ "default": "",
365
+ "description": "History period hint passed through to the MCP call; empty = default.",
366
+ "type": "string"
367
+ }
368
+ },
369
+ "type": "object"
370
+ },
371
+ "params_trader_history_fetch": {
372
+ "additionalProperties": false,
373
+ "properties": {
374
+ "limit": {
375
+ "default": 100,
376
+ "description": "Maximum closed positions to return (most recent first).",
377
+ "maximum": 1000.0,
378
+ "minimum": 1.0,
379
+ "type": "integer"
380
+ },
381
+ "trader_address": {
382
+ "description": "The trader wallet whose closed-trade history to read (required).",
383
+ "type": "string"
384
+ }
385
+ },
386
+ "required": [
387
+ "trader_address"
388
+ ],
389
+ "type": "object"
390
+ },
391
+ "params_trader_state_fetch": {
392
+ "additionalProperties": false,
393
+ "properties": {
394
+ "trader_address": {
395
+ "description": "The trader wallet whose current book to read (required).",
396
+ "type": "string"
397
+ }
398
+ },
399
+ "required": [
400
+ "trader_address"
401
+ ],
402
+ "type": "object"
403
+ },
404
+ "params_trend_structure": {
405
+ "additionalProperties": false,
406
+ "properties": {
407
+ "interval": {
408
+ "default": "4h",
409
+ "description": "Candle interval (called at 4h and 1h).",
410
+ "type": "string"
411
+ },
412
+ "lookback": {
413
+ "default": 6,
414
+ "description": "Swing lookback in bars.",
415
+ "minimum": 2.0,
416
+ "type": "integer"
417
+ }
418
+ },
419
+ "type": "object"
420
+ },
421
+ "params_ttl_dedup_state": {
422
+ "additionalProperties": false,
423
+ "properties": {
424
+ "prune_factor": {
425
+ "default": 4,
426
+ "description": "Prune entries older than prune_factor x TTL (hawk prunes at 4x).",
427
+ "minimum": 1.0,
428
+ "type": "integer"
429
+ },
430
+ "ttl_seconds": {
431
+ "default": 240,
432
+ "description": "Dedup window in seconds (stag/hawk 240, bison/thesis-fund 180, magpie 720).",
433
+ "minimum": 1.0,
434
+ "type": "integer"
435
+ }
436
+ },
437
+ "type": "object"
438
+ },
439
+ "params_universe_discover": {
440
+ "additionalProperties": false,
441
+ "properties": {
442
+ "max_leverage_cap": {
443
+ "default": 5.0,
444
+ "description": "Reject instruments whose max leverage exceeds this (magpie <=5).",
445
+ "minimum": 1.0,
446
+ "type": "number"
447
+ },
448
+ "min_day_volume": {
449
+ "default": 0.0,
450
+ "description": "Minimum dayNtlVlm floor (magpie liquidity gate).",
451
+ "minimum": 0.0,
452
+ "type": "number"
453
+ },
454
+ "name_prefix": {
455
+ "default": "",
456
+ "description": "Require instrument name to start with this prefix (magpie 'xyz:').",
457
+ "type": "string"
458
+ }
459
+ },
460
+ "type": "object"
461
+ },
462
+ "params_volume_surge_ratio": {
463
+ "additionalProperties": false,
464
+ "properties": {
465
+ "baseline_window": {
466
+ "default": 42,
467
+ "description": "Baseline window (stag 42).",
468
+ "minimum": 1.0,
469
+ "type": "integer"
470
+ },
471
+ "interval": {
472
+ "default": "4h",
473
+ "description": "Candle interval to read.",
474
+ "type": "string"
475
+ },
476
+ "recent_window": {
477
+ "default": 6,
478
+ "description": "Recent window (stag 6).",
479
+ "minimum": 1.0,
480
+ "type": "integer"
481
+ }
482
+ },
483
+ "type": "object"
484
+ }
485
+ },
486
+ "$id": "https://senpi.ai/strategy-composer/graph.schema.json",
487
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
488
+ "additionalProperties": false,
489
+ "description": "Typed dataflow DAG for a trading strategy (D1). YAML is authored; this JSON Schema is canonical (D6). YAML anchors and merge keys are banned at the document level (enforced in the validator, slice 2). Generated from the node registry \u2014 do not edit by hand.",
490
+ "properties": {
491
+ "edges": {
492
+ "description": "Wiring: from 'nodeId.outPort' to 'nodeId.inPort' (D1).",
493
+ "items": {
494
+ "additionalProperties": false,
495
+ "properties": {
496
+ "from": {
497
+ "pattern": "^[^.]+\\.[^.]+$",
498
+ "type": "string"
499
+ },
500
+ "to": {
501
+ "pattern": "^[^.]+\\.[^.]+$",
502
+ "type": "string"
503
+ }
504
+ },
505
+ "required": [
506
+ "from",
507
+ "to"
508
+ ],
509
+ "type": "object"
510
+ },
511
+ "type": "array"
512
+ },
513
+ "metadata": {
514
+ "description": "Interview answers and authoring notes (D7); free-form.",
515
+ "type": "object"
516
+ },
517
+ "nodes": {
518
+ "description": "The DAG nodes. Each is EITHER a primitive node binding a registry `node:` to params, OR a per-graph `kind: pure_fn` node (D2 kind 2) carrying declared typed inputs/outputs and an inline `fn:` body. The per-node `node`-keyed branches below apply only to primitive nodes; a pure_fn node (no `node:`) satisfies them vacuously and is checked by the validator's purity + inline-test stage.",
519
+ "items": {
520
+ "additionalProperties": false,
521
+ "allOf": [
522
+ {
523
+ "if": {
524
+ "properties": {
525
+ "node": {
526
+ "const": "acceleration"
527
+ }
528
+ }
529
+ },
530
+ "then": {
531
+ "properties": {
532
+ "with": {
533
+ "$ref": "#/$defs/params_acceleration"
534
+ }
535
+ }
536
+ }
537
+ },
538
+ {
539
+ "if": {
540
+ "properties": {
541
+ "node": {
542
+ "const": "asset_trading_limits_fetch"
543
+ }
544
+ }
545
+ },
546
+ "then": {
547
+ "properties": {
548
+ "with": {
549
+ "$ref": "#/$defs/params_asset_trading_limits_fetch"
550
+ }
551
+ }
552
+ }
553
+ },
554
+ {
555
+ "if": {
556
+ "properties": {
557
+ "node": {
558
+ "const": "breakout_detect"
559
+ }
560
+ }
561
+ },
562
+ "then": {
563
+ "properties": {
564
+ "with": {
565
+ "$ref": "#/$defs/params_breakout_detect"
566
+ }
567
+ }
568
+ }
569
+ },
570
+ {
571
+ "if": {
572
+ "properties": {
573
+ "node": {
574
+ "const": "candles_fetch"
575
+ }
576
+ }
577
+ },
578
+ "then": {
579
+ "properties": {
580
+ "with": {
581
+ "$ref": "#/$defs/params_candles_fetch"
582
+ }
583
+ }
584
+ }
585
+ },
586
+ {
587
+ "if": {
588
+ "properties": {
589
+ "node": {
590
+ "const": "classifier_predicate"
591
+ }
592
+ }
593
+ },
594
+ "then": {
595
+ "properties": {
596
+ "with": {
597
+ "$ref": "#/$defs/params_classifier_predicate"
598
+ }
599
+ }
600
+ }
601
+ },
602
+ {
603
+ "if": {
604
+ "properties": {
605
+ "node": {
606
+ "const": "clearinghouse_state"
607
+ }
608
+ }
609
+ },
610
+ "then": {
611
+ "properties": {
612
+ "with": {
613
+ "$ref": "#/$defs/params_clearinghouse_state"
614
+ }
615
+ }
616
+ }
617
+ },
618
+ {
619
+ "if": {
620
+ "properties": {
621
+ "node": {
622
+ "const": "emit_single_best"
623
+ }
624
+ }
625
+ },
626
+ "then": {
627
+ "properties": {
628
+ "with": {
629
+ "$ref": "#/$defs/params_emit_single_best"
630
+ }
631
+ }
632
+ }
633
+ },
634
+ {
635
+ "if": {
636
+ "properties": {
637
+ "node": {
638
+ "const": "hard_gates_all"
639
+ }
640
+ }
641
+ },
642
+ "then": {
643
+ "properties": {
644
+ "with": {
645
+ "$ref": "#/$defs/params_hard_gates_all"
646
+ }
647
+ }
648
+ }
649
+ },
650
+ {
651
+ "if": {
652
+ "properties": {
653
+ "node": {
654
+ "const": "held_asset_exclusion"
655
+ }
656
+ }
657
+ },
658
+ "then": {
659
+ "properties": {
660
+ "with": {
661
+ "$ref": "#/$defs/params_held_asset_exclusion"
662
+ }
663
+ }
664
+ }
665
+ },
666
+ {
667
+ "if": {
668
+ "properties": {
669
+ "node": {
670
+ "const": "instrument_list"
671
+ }
672
+ }
673
+ },
674
+ "then": {
675
+ "properties": {
676
+ "with": {
677
+ "$ref": "#/$defs/params_instrument_list"
678
+ }
679
+ }
680
+ }
681
+ },
682
+ {
683
+ "if": {
684
+ "properties": {
685
+ "node": {
686
+ "const": "live_instrument_validation"
687
+ }
688
+ }
689
+ },
690
+ "then": {
691
+ "properties": {
692
+ "with": {
693
+ "$ref": "#/$defs/params_live_instrument_validation"
694
+ }
695
+ }
696
+ }
697
+ },
698
+ {
699
+ "if": {
700
+ "properties": {
701
+ "node": {
702
+ "const": "market_prices_fetch"
703
+ }
704
+ }
705
+ },
706
+ "then": {
707
+ "properties": {
708
+ "with": {
709
+ "$ref": "#/$defs/params_market_prices_fetch"
710
+ }
711
+ }
712
+ }
713
+ },
714
+ {
715
+ "if": {
716
+ "properties": {
717
+ "node": {
718
+ "const": "open_orders_fetch"
719
+ }
720
+ }
721
+ },
722
+ "then": {
723
+ "properties": {
724
+ "with": {
725
+ "$ref": "#/$defs/params_open_orders_fetch"
726
+ }
727
+ }
728
+ }
729
+ },
730
+ {
731
+ "if": {
732
+ "properties": {
733
+ "node": {
734
+ "const": "own_return_24h"
735
+ }
736
+ }
737
+ },
738
+ "then": {
739
+ "properties": {
740
+ "with": {
741
+ "$ref": "#/$defs/params_own_return_24h"
742
+ }
743
+ }
744
+ }
745
+ },
746
+ {
747
+ "if": {
748
+ "properties": {
749
+ "node": {
750
+ "const": "pct_change"
751
+ }
752
+ }
753
+ },
754
+ "then": {
755
+ "properties": {
756
+ "with": {
757
+ "$ref": "#/$defs/params_pct_change"
758
+ }
759
+ }
760
+ }
761
+ },
762
+ {
763
+ "if": {
764
+ "properties": {
765
+ "node": {
766
+ "const": "rank_pool_cap_to_open_slots"
767
+ }
768
+ }
769
+ },
770
+ "then": {
771
+ "properties": {
772
+ "with": {
773
+ "$ref": "#/$defs/params_rank_pool_cap_to_open_slots"
774
+ }
775
+ }
776
+ }
777
+ },
778
+ {
779
+ "if": {
780
+ "properties": {
781
+ "node": {
782
+ "const": "recent_high_bars_ago"
783
+ }
784
+ }
785
+ },
786
+ "then": {
787
+ "properties": {
788
+ "with": {
789
+ "$ref": "#/$defs/params_recent_high_bars_ago"
790
+ }
791
+ }
792
+ }
793
+ },
794
+ {
795
+ "if": {
796
+ "properties": {
797
+ "node": {
798
+ "const": "recent_signal_ttl_dedup"
799
+ }
800
+ }
801
+ },
802
+ "then": {
803
+ "properties": {
804
+ "with": {
805
+ "$ref": "#/$defs/params_recent_signal_ttl_dedup"
806
+ }
807
+ }
808
+ }
809
+ },
810
+ {
811
+ "if": {
812
+ "properties": {
813
+ "node": {
814
+ "const": "rsi"
815
+ }
816
+ }
817
+ },
818
+ "then": {
819
+ "properties": {
820
+ "with": {
821
+ "$ref": "#/$defs/params_rsi"
822
+ }
823
+ }
824
+ }
825
+ },
826
+ {
827
+ "if": {
828
+ "properties": {
829
+ "node": {
830
+ "const": "signal_envelope"
831
+ }
832
+ }
833
+ },
834
+ "then": {
835
+ "properties": {
836
+ "with": {
837
+ "$ref": "#/$defs/params_signal_envelope"
838
+ }
839
+ }
840
+ }
841
+ },
842
+ {
843
+ "if": {
844
+ "properties": {
845
+ "node": {
846
+ "const": "sm_lean"
847
+ }
848
+ }
849
+ },
850
+ "then": {
851
+ "properties": {
852
+ "with": {
853
+ "$ref": "#/$defs/params_sm_lean"
854
+ }
855
+ }
856
+ }
857
+ },
858
+ {
859
+ "if": {
860
+ "properties": {
861
+ "node": {
862
+ "const": "sma"
863
+ }
864
+ }
865
+ },
866
+ "then": {
867
+ "properties": {
868
+ "with": {
869
+ "$ref": "#/$defs/params_sma"
870
+ }
871
+ }
872
+ }
873
+ },
874
+ {
875
+ "if": {
876
+ "properties": {
877
+ "node": {
878
+ "const": "strategy_list_fetch"
879
+ }
880
+ }
881
+ },
882
+ "then": {
883
+ "properties": {
884
+ "with": {
885
+ "$ref": "#/$defs/params_strategy_list_fetch"
886
+ }
887
+ }
888
+ }
889
+ },
890
+ {
891
+ "if": {
892
+ "properties": {
893
+ "node": {
894
+ "const": "strategy_pnl_snapshot"
895
+ }
896
+ }
897
+ },
898
+ "then": {
899
+ "properties": {
900
+ "with": {
901
+ "$ref": "#/$defs/params_strategy_pnl_snapshot"
902
+ }
903
+ }
904
+ }
905
+ },
906
+ {
907
+ "if": {
908
+ "properties": {
909
+ "node": {
910
+ "const": "trader_history_fetch"
911
+ }
912
+ }
913
+ },
914
+ "then": {
915
+ "properties": {
916
+ "with": {
917
+ "$ref": "#/$defs/params_trader_history_fetch"
918
+ }
919
+ }
920
+ }
921
+ },
922
+ {
923
+ "if": {
924
+ "properties": {
925
+ "node": {
926
+ "const": "trader_state_fetch"
927
+ }
928
+ }
929
+ },
930
+ "then": {
931
+ "properties": {
932
+ "with": {
933
+ "$ref": "#/$defs/params_trader_state_fetch"
934
+ }
935
+ }
936
+ }
937
+ },
938
+ {
939
+ "if": {
940
+ "properties": {
941
+ "node": {
942
+ "const": "trend_structure"
943
+ }
944
+ }
945
+ },
946
+ "then": {
947
+ "properties": {
948
+ "with": {
949
+ "$ref": "#/$defs/params_trend_structure"
950
+ }
951
+ }
952
+ }
953
+ },
954
+ {
955
+ "if": {
956
+ "properties": {
957
+ "node": {
958
+ "const": "ttl_dedup_state"
959
+ }
960
+ }
961
+ },
962
+ "then": {
963
+ "properties": {
964
+ "with": {
965
+ "$ref": "#/$defs/params_ttl_dedup_state"
966
+ }
967
+ }
968
+ }
969
+ },
970
+ {
971
+ "if": {
972
+ "properties": {
973
+ "node": {
974
+ "const": "universe_discover"
975
+ }
976
+ }
977
+ },
978
+ "then": {
979
+ "properties": {
980
+ "with": {
981
+ "$ref": "#/$defs/params_universe_discover"
982
+ }
983
+ }
984
+ }
985
+ },
986
+ {
987
+ "if": {
988
+ "properties": {
989
+ "node": {
990
+ "const": "volume_surge_ratio"
991
+ }
992
+ }
993
+ },
994
+ "then": {
995
+ "properties": {
996
+ "with": {
997
+ "$ref": "#/$defs/params_volume_surge_ratio"
998
+ }
999
+ }
1000
+ }
1001
+ }
1002
+ ],
1003
+ "properties": {
1004
+ "fn": {
1005
+ "description": "pure_fn body: exactly one top-level `def` (purity-checked).",
1006
+ "type": "string"
1007
+ },
1008
+ "id": {
1009
+ "description": "Unique node id within the graph.",
1010
+ "type": "string"
1011
+ },
1012
+ "inputs": {
1013
+ "description": "pure_fn declared typed input ports.",
1014
+ "items": {
1015
+ "additionalProperties": false,
1016
+ "properties": {
1017
+ "doc": {
1018
+ "type": "string"
1019
+ },
1020
+ "name": {
1021
+ "type": "string"
1022
+ },
1023
+ "type": {
1024
+ "enum": [
1025
+ "asset_list",
1026
+ "candles",
1027
+ "feature_map",
1028
+ "score_map",
1029
+ "signals",
1030
+ "scalar",
1031
+ "state",
1032
+ "record_list"
1033
+ ]
1034
+ }
1035
+ },
1036
+ "required": [
1037
+ "name",
1038
+ "type"
1039
+ ],
1040
+ "type": "object"
1041
+ },
1042
+ "type": "array"
1043
+ },
1044
+ "kind": {
1045
+ "description": "Marks a per-graph pure-function node (D2 kind 2).",
1046
+ "enum": [
1047
+ "pure_fn"
1048
+ ]
1049
+ },
1050
+ "node": {
1051
+ "description": "Registry node name (primitive nodes only).",
1052
+ "enum": [
1053
+ "acceleration",
1054
+ "asset_trading_limits_fetch",
1055
+ "breakout_detect",
1056
+ "candles_fetch",
1057
+ "classifier_predicate",
1058
+ "clearinghouse_state",
1059
+ "emit_single_best",
1060
+ "hard_gates_all",
1061
+ "held_asset_exclusion",
1062
+ "instrument_list",
1063
+ "live_instrument_validation",
1064
+ "market_prices_fetch",
1065
+ "open_orders_fetch",
1066
+ "own_return_24h",
1067
+ "pct_change",
1068
+ "rank_pool_cap_to_open_slots",
1069
+ "recent_high_bars_ago",
1070
+ "recent_signal_ttl_dedup",
1071
+ "rsi",
1072
+ "signal_envelope",
1073
+ "sm_lean",
1074
+ "sma",
1075
+ "strategy_list_fetch",
1076
+ "strategy_pnl_snapshot",
1077
+ "trader_history_fetch",
1078
+ "trader_state_fetch",
1079
+ "trend_structure",
1080
+ "ttl_dedup_state",
1081
+ "universe_discover",
1082
+ "volume_surge_ratio"
1083
+ ],
1084
+ "type": "string"
1085
+ },
1086
+ "outputs": {
1087
+ "description": "pure_fn declared typed output ports.",
1088
+ "items": {
1089
+ "additionalProperties": false,
1090
+ "properties": {
1091
+ "doc": {
1092
+ "type": "string"
1093
+ },
1094
+ "name": {
1095
+ "type": "string"
1096
+ },
1097
+ "type": {
1098
+ "enum": [
1099
+ "asset_list",
1100
+ "candles",
1101
+ "feature_map",
1102
+ "score_map",
1103
+ "signals",
1104
+ "scalar",
1105
+ "state",
1106
+ "record_list"
1107
+ ]
1108
+ }
1109
+ },
1110
+ "required": [
1111
+ "name",
1112
+ "type"
1113
+ ],
1114
+ "type": "object"
1115
+ },
1116
+ "type": "array"
1117
+ },
1118
+ "params": {
1119
+ "description": "pure_fn literal params (config, not edges).",
1120
+ "items": {
1121
+ "additionalProperties": false,
1122
+ "properties": {
1123
+ "default": {},
1124
+ "doc": {
1125
+ "type": "string"
1126
+ },
1127
+ "name": {
1128
+ "type": "string"
1129
+ },
1130
+ "type": {
1131
+ "enum": [
1132
+ "int",
1133
+ "float",
1134
+ "str",
1135
+ "bool",
1136
+ "list[str]",
1137
+ "map_str_float"
1138
+ ]
1139
+ }
1140
+ },
1141
+ "required": [
1142
+ "name",
1143
+ "type"
1144
+ ],
1145
+ "type": "object"
1146
+ },
1147
+ "type": "array"
1148
+ },
1149
+ "tests": {
1150
+ "description": "pure_fn inline fixture tests, run at validate time.",
1151
+ "items": {
1152
+ "additionalProperties": false,
1153
+ "properties": {
1154
+ "expect": {
1155
+ "type": "object"
1156
+ },
1157
+ "inputs": {
1158
+ "type": "object"
1159
+ },
1160
+ "name": {
1161
+ "type": "string"
1162
+ }
1163
+ },
1164
+ "required": [
1165
+ "name",
1166
+ "inputs",
1167
+ "expect"
1168
+ ],
1169
+ "type": "object"
1170
+ },
1171
+ "type": "array"
1172
+ },
1173
+ "with": {
1174
+ "description": "Node parameters.",
1175
+ "type": "object"
1176
+ }
1177
+ },
1178
+ "required": [
1179
+ "id"
1180
+ ],
1181
+ "type": "object"
1182
+ },
1183
+ "minItems": 1,
1184
+ "type": "array"
1185
+ },
1186
+ "pipeline": {
1187
+ "description": "RESERVED shorthand marker for the common linear case (D1/D6). Desugaring into nodes+edges is slice 2 and is NOT built here.",
1188
+ "items": {
1189
+ "type": "string"
1190
+ },
1191
+ "type": "array"
1192
+ },
1193
+ "version": {
1194
+ "const": 1,
1195
+ "description": "Registry/schema version."
1196
+ }
1197
+ },
1198
+ "required": [
1199
+ "nodes"
1200
+ ],
1201
+ "title": "Strategy Composer Graph",
1202
+ "type": "object"
1203
+ }