openbroker 1.9.2 → 1.9.4

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 (69) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +16 -0
  3. package/SKILL.md +69 -3
  4. package/dist/auto/cli.js +4 -1
  5. package/dist/auto/examples/dca.d.ts +2 -1
  6. package/dist/auto/examples/dca.d.ts.map +1 -1
  7. package/dist/auto/examples/dca.js +19 -1
  8. package/dist/auto/examples/funding-arb.d.ts +2 -1
  9. package/dist/auto/examples/funding-arb.d.ts.map +1 -1
  10. package/dist/auto/examples/funding-arb.js +19 -2
  11. package/dist/auto/examples/grid.d.ts +2 -1
  12. package/dist/auto/examples/grid.d.ts.map +1 -1
  13. package/dist/auto/examples/grid.js +18 -2
  14. package/dist/auto/examples/mm-maker.d.ts +2 -1
  15. package/dist/auto/examples/mm-maker.d.ts.map +1 -1
  16. package/dist/auto/examples/mm-maker.js +18 -2
  17. package/dist/auto/examples/mm-spread.d.ts +2 -1
  18. package/dist/auto/examples/mm-spread.d.ts.map +1 -1
  19. package/dist/auto/examples/mm-spread.js +18 -2
  20. package/dist/auto/examples/price-alert.d.ts +2 -1
  21. package/dist/auto/examples/price-alert.d.ts.map +1 -1
  22. package/dist/auto/examples/price-alert.js +2 -1
  23. package/dist/auto/guardrails.d.ts +19 -0
  24. package/dist/auto/guardrails.d.ts.map +1 -0
  25. package/dist/auto/guardrails.js +575 -0
  26. package/dist/auto/guardrails.test.d.ts +2 -0
  27. package/dist/auto/guardrails.test.d.ts.map +1 -0
  28. package/dist/auto/guardrails.test.js +173 -0
  29. package/dist/auto/loader.d.ts +3 -3
  30. package/dist/auto/loader.d.ts.map +1 -1
  31. package/dist/auto/loader.js +25 -3
  32. package/dist/auto/realtime.d.ts +45 -0
  33. package/dist/auto/realtime.d.ts.map +1 -0
  34. package/dist/auto/realtime.js +177 -0
  35. package/dist/auto/realtime.test.d.ts +2 -0
  36. package/dist/auto/realtime.test.d.ts.map +1 -0
  37. package/dist/auto/realtime.test.js +73 -0
  38. package/dist/auto/runtime.d.ts +3 -3
  39. package/dist/auto/runtime.d.ts.map +1 -1
  40. package/dist/auto/runtime.js +155 -65
  41. package/dist/auto/types.d.ts +45 -1
  42. package/dist/auto/types.d.ts.map +1 -1
  43. package/dist/core/client.d.ts +66 -1
  44. package/dist/core/client.d.ts.map +1 -1
  45. package/dist/core/client.js +141 -4
  46. package/dist/core/ws.d.ts +14 -2
  47. package/dist/core/ws.d.ts.map +1 -1
  48. package/dist/core/ws.js +53 -7
  49. package/dist/lib.d.ts +2 -0
  50. package/dist/lib.d.ts.map +1 -1
  51. package/dist/lib.js +1 -0
  52. package/package.json +5 -3
  53. package/scripts/auto/cli.ts +4 -1
  54. package/scripts/auto/examples/dca.ts +21 -2
  55. package/scripts/auto/examples/funding-arb.ts +21 -3
  56. package/scripts/auto/examples/grid.ts +20 -3
  57. package/scripts/auto/examples/mm-maker.ts +20 -3
  58. package/scripts/auto/examples/mm-spread.ts +20 -3
  59. package/scripts/auto/examples/price-alert.ts +4 -2
  60. package/scripts/auto/guardrails.test.ts +227 -0
  61. package/scripts/auto/guardrails.ts +700 -0
  62. package/scripts/auto/loader.ts +41 -4
  63. package/scripts/auto/realtime.test.ts +84 -0
  64. package/scripts/auto/realtime.ts +194 -0
  65. package/scripts/auto/runtime.ts +163 -69
  66. package/scripts/auto/types.ts +56 -1
  67. package/scripts/core/client.ts +175 -4
  68. package/scripts/core/ws.ts +57 -8
  69. package/scripts/lib.ts +10 -0
@@ -3,11 +3,13 @@
3
3
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
4
4
  import path from 'path';
5
5
  import os from 'os';
6
- import { getClient } from '../core/client.js';
6
+ import { HyperliquidClient } from '../core/client.js';
7
7
  import { roundPrice, roundSize, sleep, normalizeCoin, formatUsd, formatPercent, annualizeFundingRate, } from '../core/utils.js';
8
8
  import { WebSocketManager } from '../core/ws.js';
9
+ import { AutomationRealtimeData } from './realtime.js';
9
10
  import { AutomationEventBus } from './events.js';
10
11
  import { loadAutomation } from './loader.js';
12
+ import { CLIENT_WRITE_METHODS, createGuardrailedClient } from './guardrails.js';
11
13
  import { registerAutomation, unregisterAutomation, getRegisteredAutomations as getRegisteredFromFile } from './registry.js';
12
14
  import { createAutomationAudit, toSerializable } from './audit.js';
13
15
  import { startKeepAwake } from './keep-awake.js';
@@ -74,12 +76,6 @@ function fanOutAgentAction(observers, action, status, details, txHash) {
74
76
  }
75
77
  }
76
78
  const STATE_DIR = path.join(os.homedir(), '.openbroker', 'state');
77
- const AUDITED_WRITE_METHODS = new Set([
78
- 'order', 'marketOrder', 'limitOrder', 'triggerOrder',
79
- 'takeProfit', 'stopLoss', 'cancel', 'cancelAll',
80
- 'spotOrder', 'spotMarketOrder', 'spotLimitOrder', 'spotCancel',
81
- 'updateLeverage', 'approveBuilderFee', 'twapOrder', 'twapCancel',
82
- ]);
83
79
  function createState(id) {
84
80
  mkdirSync(STATE_DIR, { recursive: true });
85
81
  const stateFile = path.join(STATE_DIR, `${id}.json`);
@@ -157,18 +153,11 @@ function createLogger(id, verbose, audit) {
157
153
  };
158
154
  }
159
155
  // ── Dry-run client proxy ────────────────────────────────────────────
160
- const WRITE_METHODS = new Set([
161
- 'order', 'marketOrder', 'limitOrder', 'triggerOrder',
162
- 'takeProfit', 'stopLoss', 'cancel', 'cancelAll',
163
- 'updateLeverage', 'approveBuilderFee',
164
- 'spotOrder', 'spotMarketOrder', 'spotLimitOrder', 'spotCancel',
165
- 'twapOrder', 'twapCancel',
166
- ]);
167
156
  function createDryClient(client, log) {
168
157
  return new Proxy(client, {
169
158
  get(target, prop, receiver) {
170
159
  const value = Reflect.get(target, prop, receiver);
171
- if (typeof prop === 'string' && WRITE_METHODS.has(prop) && typeof value === 'function') {
160
+ if (typeof prop === 'string' && CLIENT_WRITE_METHODS.has(prop) && typeof value === 'function') {
172
161
  return (...args) => {
173
162
  log.info(`[DRY] ${prop}(${args.map(a => JSON.stringify(a)).join(', ')})`);
174
163
  return Promise.resolve({ status: 'ok', response: { type: 'dry_run' } });
@@ -182,7 +171,7 @@ function createAuditedClient(client, audit, dryRun, observers) {
182
171
  return new Proxy(client, {
183
172
  get(target, prop, receiver) {
184
173
  const value = Reflect.get(target, prop, receiver);
185
- if (typeof prop === 'string' && AUDITED_WRITE_METHODS.has(prop) && typeof value === 'function') {
174
+ if (typeof prop === 'string' && CLIENT_WRITE_METHODS.has(prop) && typeof value === 'function') {
186
175
  return async (...args) => {
187
176
  const actionId = `${prop}:${Date.now()}:${Math.random().toString(16).slice(2)}`;
188
177
  audit.recordAction({
@@ -356,8 +345,8 @@ export function getAutomation(id) {
356
345
  export { getRegisteredFromFile as getRegisteredAutomations };
357
346
  export async function startAutomation(options) {
358
347
  const { scriptPath, dryRun = false, verbose = false, gatewayPort, hooksToken, initialState, useWebSocket = true, } = options;
359
- // When WebSocket is enabled, REST poll becomes a heartbeat (30s default)
360
- // When disabled, use the original 10s polling interval
348
+ // This is the disconnected REST fallback cadence. While WebSocket is live,
349
+ // reconciliation is clamped to at least 60 seconds below.
361
350
  const pollIntervalMs = options.pollIntervalMs ?? (useWebSocket ? 30_000 : 10_000);
362
351
  const id = options.id || path.basename(scriptPath, '.ts');
363
352
  if (registry.has(id)) {
@@ -371,7 +360,10 @@ export async function startAutomation(options) {
371
360
  }
372
361
  }
373
362
  const eventBus = new AutomationEventBus();
374
- const rawClient = getClient();
363
+ // Each automation owns its client + realtime cache. This prevents one run
364
+ // from replacing or detaching another run's WebSocket provider when several
365
+ // automations share a host process.
366
+ const rawClient = new HyperliquidClient();
375
367
  const audit = createAutomationAudit({
376
368
  automationId: id,
377
369
  scriptPath,
@@ -396,8 +388,39 @@ export async function startAutomation(options) {
396
388
  }
397
389
  }
398
390
  const observers = await loadConventionObservers(log);
391
+ let loaded;
392
+ try {
393
+ log.info(`Loading automation: ${scriptPath}`);
394
+ loaded = await loadAutomation(scriptPath, { config: stateController.snapshot() });
395
+ }
396
+ catch (err) {
397
+ const error = err instanceof Error ? err : new Error(String(err));
398
+ audit.recordError('guardrail_validation', error);
399
+ await audit.stop({
400
+ status: 'error',
401
+ stopReason: 'guardrail_validation_error',
402
+ pollCount: 0,
403
+ eventsEmitted: 0,
404
+ });
405
+ keepAwake?.stop();
406
+ throw error;
407
+ }
408
+ audit.recordNote('guardrails', loaded.guardrails);
399
409
  const baseClient = dryRun ? createDryClient(rawClient, log) : rawClient;
400
- const client = createAuditedClient(baseClient, audit, dryRun, observers);
410
+ const guardedClient = createGuardrailedClient(baseClient, {
411
+ policy: loaded.guardrails,
412
+ rawClient,
413
+ log,
414
+ onViolation: (error, method, args) => {
415
+ audit.recordNote('guardrail_block', {
416
+ code: error.code,
417
+ message: error.message,
418
+ method,
419
+ args: toSerializable(args),
420
+ });
421
+ },
422
+ });
423
+ const client = createAuditedClient(guardedClient, audit, dryRun, observers);
401
424
  const startHooks = [];
402
425
  const stopHooks = [];
403
426
  const errorHooks = [];
@@ -418,7 +441,7 @@ export async function startAutomation(options) {
418
441
  client,
419
442
  utils: { roundPrice, roundSize, sleep, normalizeCoin, formatUsd, formatPercent, annualizeFundingRate },
420
443
  on: (event, handler) => eventBus.on(event, handler),
421
- every: (intervalMs, handler) => scheduledTasks.push({ intervalMs, handler, lastRun: 0 }),
444
+ every: (intervalMs, handler) => scheduledTasks.push({ intervalMs, handler, lastRun: Date.now() }),
422
445
  onStart: (handler) => startHooks.push(handler),
423
446
  onStop: (handler) => stopHooks.push(handler),
424
447
  onError: (handler) => errorHooks.push(handler),
@@ -428,23 +451,11 @@ export async function startAutomation(options) {
428
451
  audit: auditApi,
429
452
  id,
430
453
  dryRun,
454
+ guardrails: loaded.guardrails,
431
455
  };
432
456
  try {
433
- // Load and execute the factory function (registers handlers)
434
- log.info(`Loading automation: ${scriptPath}`);
435
- const factory = await loadAutomation(scriptPath);
436
- await factory(api);
437
- // Call onStart hooks
438
- for (const hook of startHooks) {
439
- try {
440
- await hook();
441
- }
442
- catch (err) {
443
- const error = err instanceof Error ? err : new Error(String(err));
444
- audit.recordError('onStart', error);
445
- log.error(`onStart hook error: ${error.message}`);
446
- }
447
- }
457
+ // Execute the already validated factory function (registers handlers).
458
+ await loaded.factory(api);
448
459
  }
449
460
  catch (err) {
450
461
  const error = err instanceof Error ? err : new Error(String(err));
@@ -464,6 +475,7 @@ export async function startAutomation(options) {
464
475
  let eventsEmitted = 0;
465
476
  let isPolling = false;
466
477
  let stopped = false;
478
+ let automationReady = false;
467
479
  async function handleErrors(errors) {
468
480
  for (const err of errors) {
469
481
  audit.recordError('handler', err);
@@ -491,11 +503,19 @@ export async function startAutomation(options) {
491
503
  // ── WebSocket setup ─────────────────────────────────────────────
492
504
  let ws = null;
493
505
  let wsConnected = false;
506
+ let realtimeData = null;
494
507
  // Track latest prices from WebSocket for real-time price_change events
495
508
  let wsPrices = new Map();
509
+ let wsFundingRates = new Map();
496
510
  if (useWebSocket) {
497
511
  try {
498
512
  ws = new WebSocketManager(verbose);
513
+ const unified = await rawClient.isUnifiedAccount().catch(() => null);
514
+ const orderDexes = await rawClient.getPerpDexs()
515
+ .then((dexes) => dexes.slice(1).flatMap((dex) => dex?.name ? [dex.name] : []))
516
+ .catch(() => []);
517
+ realtimeData = new AutomationRealtimeData(ws, rawClient, rawClient.address, unified, orderDexes);
518
+ rawClient.setRealtimeDataProvider(realtimeData);
499
519
  // Wire WebSocket events to the automation event bus
500
520
  ws.on('allMids', ({ mids }) => {
501
521
  const now = Date.now();
@@ -505,7 +525,7 @@ export async function startAutomation(options) {
505
525
  continue;
506
526
  const oldPrice = wsPrices.get(coin);
507
527
  wsPrices.set(coin, newPrice);
508
- if (oldPrice !== undefined && oldPrice !== 0 && eventBus.has('price_change')) {
528
+ if (automationReady && oldPrice !== undefined && oldPrice !== 0 && eventBus.has('price_change')) {
509
529
  const changePct = ((newPrice - oldPrice) / oldPrice) * 100;
510
530
  if (Math.abs(changePct) >= 0.01) {
511
531
  void emitAutomationEvent('price_change', { coin, oldPrice, newPrice, changePct }, 'ws');
@@ -513,6 +533,23 @@ export async function startAutomation(options) {
513
533
  }
514
534
  }
515
535
  });
536
+ ws.on('allDexsAssetCtxs', ({ ctxs }) => {
537
+ if (!automationReady || !eventBus.has('funding_update'))
538
+ return;
539
+ const next = rawClient.fundingRatesFromWs(ctxs);
540
+ for (const [coin, data] of next) {
541
+ const previous = wsFundingRates.get(coin);
542
+ wsFundingRates.set(coin, data.rate);
543
+ if (previous === undefined || previous === data.rate)
544
+ continue;
545
+ void emitAutomationEvent('funding_update', {
546
+ coin,
547
+ fundingRate: data.rate,
548
+ annualized: annualizeFundingRate(data.rate),
549
+ premium: data.premium,
550
+ }, 'ws');
551
+ }
552
+ });
516
553
  ws.on('orderUpdate', (update) => {
517
554
  audit.recordOrderUpdate({
518
555
  coin: update.order.coin,
@@ -525,7 +562,7 @@ export async function startAutomation(options) {
525
562
  statusTimestamp: update.statusTimestamp,
526
563
  raw: update,
527
564
  });
528
- if (eventBus.has('order_update')) {
565
+ if (automationReady && eventBus.has('order_update')) {
529
566
  void emitAutomationEvent('order_update', {
530
567
  coin: update.order.coin,
531
568
  oid: update.order.oid,
@@ -566,7 +603,7 @@ export async function startAutomation(options) {
566
603
  // Fee is converted to USD using feeToken: for non-USDC fees (spot
567
604
  // buys pay in the received asset), fee × price yields USD since the
568
605
  // fee token is the base of the traded pair and `price` is quote/base.
569
- if (eventBus.has('order_filled')) {
606
+ if (automationReady && eventBus.has('order_filled')) {
570
607
  const size = parseFloat(fill.sz);
571
608
  const price = parseFloat(fill.px);
572
609
  const rawFee = parseFloat(fill.fee);
@@ -600,7 +637,7 @@ export async function startAutomation(options) {
600
637
  ws.on('userEvent', (event) => {
601
638
  audit.recordUserEvent(event);
602
639
  // Handle liquidation events — only available through WebSocket
603
- if ('liquidation' in event && eventBus.has('liquidation')) {
640
+ if (automationReady && 'liquidation' in event && eventBus.has('liquidation')) {
604
641
  const liq = event.liquidation;
605
642
  void emitAutomationEvent('liquidation', {
606
643
  lid: liq.lid,
@@ -623,10 +660,18 @@ export async function startAutomation(options) {
623
660
  wsConnected = true;
624
661
  log.info('WebSocket connected — real-time events active');
625
662
  });
626
- // Connect and subscribe
663
+ // Connect subscriptions and warm only the main static universe in
664
+ // parallel. HIP-3 metadata is loaded lazily when referenced.
627
665
  const userAddress = rawClient.address;
628
- await ws.subscribeAll(userAddress);
629
- log.info('WebSocket subscriptions active (allMids, orderUpdates, userFills, userEvents)');
666
+ await Promise.all([
667
+ ws.subscribeAll(userAddress, orderDexes),
668
+ rawClient.initializeRealtimeMetadata().catch((error) => {
669
+ log.warn(`Realtime metadata warmup failed: ${error instanceof Error ? error.message : String(error)}; REST fallback remains available`);
670
+ }),
671
+ ]);
672
+ const seeded = await realtimeData.waitUntilReady();
673
+ const readiness = realtimeData.readinessSummary();
674
+ log.info(`WebSocket subscriptions active (mids, asset contexts, account state, spot state, orders, fills, user events)${seeded ? '' : ` · initial snapshots incomplete; REST fallback armed · openOrders ${readiness.seededOrderDexes}/${readiness.expectedOrderDexes}`}`);
630
675
  }
631
676
  catch (err) {
632
677
  const error = err instanceof Error ? err : new Error(String(err));
@@ -635,6 +680,8 @@ export async function startAutomation(options) {
635
680
  log.debug(`WebSocket setup stack: ${error.stack}`);
636
681
  }
637
682
  log.warn(`WebSocket setup failed: ${error.message} — using REST polling only`);
683
+ rawClient.setRealtimeDataProvider(null);
684
+ realtimeData = null;
638
685
  ws = null;
639
686
  wsConnected = false;
640
687
  }
@@ -671,7 +718,7 @@ export async function startAutomation(options) {
671
718
  }
672
719
  }
673
720
  // Funding updates
674
- if (eventBus.has('funding_update')) {
721
+ if (eventBus.has('funding_update') && !wsConnected) {
675
722
  for (const [coin, data] of snapshot.fundingRates) {
676
723
  await emitAutomationEvent('funding_update', {
677
724
  coin,
@@ -752,21 +799,6 @@ export async function startAutomation(options) {
752
799
  // Order filled — compare open order IDs
753
800
  // (Skipped for MVP — requires tracking open orders per poll, will add when needed)
754
801
  }
755
- // Run scheduled tasks
756
- for (const task of scheduledTasks) {
757
- if (now - task.lastRun >= task.intervalMs) {
758
- try {
759
- await task.handler();
760
- }
761
- catch (err) {
762
- const error = err instanceof Error ? err : new Error(String(err));
763
- audit.recordError('scheduled_task', error);
764
- log.error(`Scheduled task error: ${error.message}`);
765
- await handleErrors([error]);
766
- }
767
- task.lastRun = now;
768
- }
769
- }
770
802
  previousSnapshot = snapshot;
771
803
  }
772
804
  catch (err) {
@@ -778,24 +810,82 @@ export async function startAutomation(options) {
778
810
  isPolling = false;
779
811
  }
780
812
  }
781
- // Start polling
782
- const wsLabel = wsConnected ? ', ws=on' : (useWebSocket ? ', ws=failed' : '');
783
- log.info(`Started (poll every ${pollIntervalMs / 1000}s, dry=${dryRun}${wsLabel})`);
784
- const timer = setInterval(poll, pollIntervalMs);
785
- // Initial poll to seed state
813
+ async function runScheduledTasks() {
814
+ const now = Date.now();
815
+ for (const task of scheduledTasks) {
816
+ if (task.running || now - task.lastRun < task.intervalMs)
817
+ continue;
818
+ task.running = true;
819
+ task.lastRun = now;
820
+ try {
821
+ await task.handler();
822
+ }
823
+ catch (err) {
824
+ const error = err instanceof Error ? err : new Error(String(err));
825
+ audit.recordError('scheduled_task', error);
826
+ log.error(`Scheduled task error: ${error.message}`);
827
+ await handleErrors([error]);
828
+ }
829
+ finally {
830
+ task.running = false;
831
+ }
832
+ }
833
+ }
834
+ // Seed an audit snapshot. With a healthy socket this is assembled from the
835
+ // live cache; REST is used only for any feed that has not produced its first
836
+ // snapshot yet.
786
837
  await poll();
838
+ // Start hooks run after WebSocket caches are seeded, so strategy reads are
839
+ // WebSocket-first from their very first decision.
840
+ for (const hook of startHooks) {
841
+ try {
842
+ await hook();
843
+ }
844
+ catch (err) {
845
+ const error = err instanceof Error ? err : new Error(String(err));
846
+ audit.recordError('onStart', error);
847
+ log.error(`onStart hook error: ${error.message}`);
848
+ for (const errorHook of errorHooks) {
849
+ try {
850
+ await errorHook(error);
851
+ }
852
+ catch { /* swallow */ }
853
+ }
854
+ }
855
+ }
856
+ automationReady = true;
857
+ // api.every() is a real scheduler now; it no longer depends on how often a
858
+ // heavyweight REST reconciliation snapshot runs.
859
+ const scheduleTimer = setInterval(() => { void runScheduledTasks(); }, 500);
860
+ // --poll controls the REST fallback cadence while the socket is down. While
861
+ // connected, reconcile at most once per minute regardless of a shorter
862
+ // fallback interval supplied by older launch commands.
863
+ const restReconcileMs = Math.max(60_000, pollIntervalMs);
864
+ let lastPollAt = Date.now();
865
+ const pollTimer = setInterval(() => {
866
+ const interval = wsConnected ? restReconcileMs : pollIntervalMs;
867
+ if (Date.now() - lastPollAt < interval)
868
+ return;
869
+ lastPollAt = Date.now();
870
+ void poll();
871
+ }, Math.min(1_000, pollIntervalMs));
872
+ const wsLabel = wsConnected ? ', ws=on' : (useWebSocket ? ', ws=failed' : '');
873
+ log.info(`Started (REST fallback ${pollIntervalMs / 1000}s, connected reconcile ${restReconcileMs / 1000}s, dry=${dryRun}${wsLabel})`);
787
874
  // Stop function
788
875
  async function stop(opts) {
789
876
  if (stopped)
790
877
  return;
791
878
  stopped = true;
792
- clearInterval(timer);
879
+ clearInterval(scheduleTimer);
880
+ clearInterval(pollTimer);
793
881
  // Close WebSocket
794
882
  if (ws) {
795
883
  ws.removeAllListeners();
796
884
  await ws.close();
797
885
  ws = null;
798
886
  }
887
+ rawClient.setRealtimeDataProvider(null);
888
+ realtimeData = null;
799
889
  for (const hook of stopHooks) {
800
890
  try {
801
891
  await hook();
@@ -1,6 +1,47 @@
1
1
  import type { HyperliquidClient } from '../core/client.js';
2
2
  /** What an automation .ts file exports */
3
3
  export type AutomationFactory = (api: AutomationAPI) => void | Promise<void>;
4
+ /** Runtime-enforced policy exported by every automation module. */
5
+ export type AutomationGuardrails = ReadOnlyAutomationGuardrails | TradingAutomationGuardrails;
6
+ export interface ReadOnlyAutomationGuardrails {
7
+ /** Read-only automations cannot call any client write method. */
8
+ mode: 'read-only';
9
+ }
10
+ export interface TradingAutomationGuardrails {
11
+ mode: 'trading';
12
+ /** Canonical markets this automation may trade: `ETH`, `xyz:CL`, `spot:HYPE`, `#1230`. */
13
+ allowedMarkets: string[];
14
+ /** Maximum USD notional for one submitted order. */
15
+ maxOrderUsd: number;
16
+ /** Maximum absolute USD exposure in any one market after an order. */
17
+ maxPositionUsd: number;
18
+ /** Maximum absolute USD exposure across the account after an order. */
19
+ maxTotalExposureUsd: number;
20
+ /** Maximum leverage the automation may request or use when increasing perp exposure. */
21
+ maxLeverage: number;
22
+ /** Maximum account margin utilization allowed after a risk-increasing perp order. */
23
+ maxMarginUsedPct: number;
24
+ /** Maximum account-wide open orders after this automation submits an order. */
25
+ maxOpenOrders: number;
26
+ /** Maximum risk-increasing order submissions in a rolling 60-second window. */
27
+ maxOrdersPerMinute: number;
28
+ /** Maximum slippage passed to market-order helpers. */
29
+ maxSlippageBps: number;
30
+ /** Whether market-order helpers may be used. */
31
+ allowMarketOrders: boolean;
32
+ /** Whether `cancelAll()` without a market or an armed `scheduleCancel()` is allowed. */
33
+ allowAccountWideCancel: boolean;
34
+ }
35
+ export interface AutomationGuardrailContext {
36
+ /** Persisted automation state with current `--set` overrides applied. */
37
+ config: Readonly<Record<string, unknown>>;
38
+ }
39
+ /** Guardrails may be static or derived from startup config, but the result is always validated. */
40
+ export type AutomationGuardrailsExport = AutomationGuardrails | ((context: AutomationGuardrailContext) => AutomationGuardrails);
41
+ export interface LoadedAutomation {
42
+ factory: AutomationFactory;
43
+ guardrails: AutomationGuardrails;
44
+ }
4
45
  /** Config field descriptor for example automations */
5
46
  export interface AutomationConfigField {
6
47
  type: 'string' | 'number' | 'boolean';
@@ -160,7 +201,7 @@ export interface AutomationAPI {
160
201
  };
161
202
  /** Subscribe to a market/account event */
162
203
  on<E extends AutomationEventType>(event: E, handler: AutomationEventHandler<E>): void;
163
- /** Run a handler on a recurring interval (ms). Aligned to the poll loop. */
204
+ /** Run a handler on its own recurring scheduler, independent of REST reconciliation. */
164
205
  every(intervalMs: number, handler: () => void | Promise<void>): void;
165
206
  /** Called after all handlers are registered and polling begins */
166
207
  onStart(handler: () => void | Promise<void>): void;
@@ -188,6 +229,8 @@ export interface AutomationAPI {
188
229
  id: string;
189
230
  /** True if running in --dry mode (write methods are intercepted) */
190
231
  dryRun: boolean;
232
+ /** Validated policy currently enforced by the runtime client proxy. */
233
+ guardrails: Readonly<AutomationGuardrails>;
191
234
  }
192
235
  export interface AutomationSnapshot {
193
236
  prices: Map<string, number>;
@@ -216,6 +259,7 @@ export interface ScheduledTask {
216
259
  intervalMs: number;
217
260
  handler: () => void | Promise<void>;
218
261
  lastRun: number;
262
+ running?: boolean;
219
263
  }
220
264
  export interface RunningAutomation {
221
265
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../scripts/auto/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../scripts/auto/types.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,38 @@
1
- import type { OpenBrokerConfig, BuilderInfo, OrderResponse, CancelResponse, MetaAndAssetCtxs, ClearinghouseState, OpenOrder, OutcomeMetaResponse, OutcomeMarket } from './types.js';
1
+ import type { OpenBrokerConfig, BuilderInfo, OrderResponse, CancelResponse, MetaAndAssetCtxs, AssetCtx, ClearinghouseState, OpenOrder, OutcomeMetaResponse, OutcomeMarket } from './types.js';
2
+ export interface RealtimeBookSnapshot {
3
+ coin: string;
4
+ time: number;
5
+ levels: [
6
+ Array<{
7
+ px: string;
8
+ sz: string;
9
+ n: number;
10
+ }>,
11
+ Array<{
12
+ px: string;
13
+ sz: string;
14
+ n: number;
15
+ }>
16
+ ];
17
+ }
18
+ export interface RealtimeDataProvider {
19
+ readonly connected: boolean;
20
+ getAllMids(): Record<string, string> | null;
21
+ getMainAssetCtxs(): AssetCtx[] | null;
22
+ getUserState(user: string, dex?: string): ClearinghouseState | null;
23
+ getUserStateAll(user: string): ClearinghouseState | null;
24
+ getSpotBalances(user: string): {
25
+ balances: Array<{
26
+ coin: string;
27
+ token: number;
28
+ hold: string;
29
+ total: string;
30
+ entryNtl: string;
31
+ }>;
32
+ } | null;
33
+ getOpenOrders(user: string): OpenOrder[] | null;
34
+ getL2Book(coin: string): Promise<RealtimeBookSnapshot | null>;
35
+ }
2
36
  export declare class HyperliquidClient {
3
37
  private config;
4
38
  private account;
@@ -10,6 +44,8 @@ export declare class HyperliquidClient {
10
44
  private szDecimalsMap;
11
45
  /** Maps coin name → dex info for HIP-3 assets. Main dex assets have dexName=null */
12
46
  private coinDexMap;
47
+ /** Static positional universe per dex, used to join allDexsAssetCtxs WS pushes. */
48
+ private dexUniverseMap;
13
49
  /** Cache of perpDexs list */
14
50
  private perpDexsCache;
15
51
  /** Whether HIP-3 assets have been loaded into maps */
@@ -40,6 +76,13 @@ export declare class HyperliquidClient {
40
76
  private spotMetaLoaded;
41
77
  /** HIP-4 outcome metadata cache */
42
78
  private outcomeMeta;
79
+ /** Static main-dex universe retained while live asset contexts arrive over WebSocket. */
80
+ private staticMeta;
81
+ /** Runtime-owned live data cache. CLI calls leave this detached and remain REST-only. */
82
+ private realtime;
83
+ private predictedFundingsCache;
84
+ private predictedFundingsInFlight;
85
+ private spotMetaCache;
43
86
  verbose: boolean;
44
87
  constructor(config?: OpenBrokerConfig);
45
88
  private log;
@@ -61,6 +104,8 @@ export declare class HyperliquidClient {
61
104
  get isReadOnly(): boolean;
62
105
  /** Whether connected to testnet (HIP-3 dexes not auto-loaded) */
63
106
  get isTestnet(): boolean;
107
+ /** Attach/detach the automation runtime's WebSocket-first data cache. */
108
+ setRealtimeDataProvider(provider: RealtimeDataProvider | null): void;
64
109
  /**
65
110
  * Returns vaultAddress param for SDK exchange calls.
66
111
  * Only used for vault trading (HYPERLIQUID_VAULT_ADDRESS set explicitly).
@@ -70,6 +115,13 @@ export declare class HyperliquidClient {
70
115
  /** Throw error if trying to trade in read-only mode. Validates API wallet on first call. */
71
116
  private requireTrading;
72
117
  getMetaAndAssetCtxs(): Promise<MetaAndAssetCtxs>;
118
+ /**
119
+ * Warm only the native/main static universe for an automation runtime.
120
+ * Dynamic contexts arrive via allDexsAssetCtxs, and HIP-3 metadata is loaded
121
+ * on demand when a strategy references a prefixed market. This avoids the
122
+ * old startup burst that fetched every HIP-3 dex before the socket opened.
123
+ */
124
+ initializeRealtimeMetadata(): Promise<void>;
73
125
  /**
74
126
  * Load HIP-3 perp dex assets into the asset/szDecimals maps.
75
127
  * Asset index formula: 100000 + dexIdx * 10000 + assetIdx
@@ -253,6 +305,7 @@ export declare class HyperliquidClient {
253
305
  nextFundingTime: number;
254
306
  }]>
255
307
  ]>>;
308
+ private fetchPredictedFundings;
256
309
  /**
257
310
  * Get L2 order book for an asset
258
311
  * Returns best bid/ask and depth
@@ -274,6 +327,7 @@ export declare class HyperliquidClient {
274
327
  spread: number;
275
328
  spreadBps: number;
276
329
  }>;
330
+ private normalizeL2Book;
277
331
  getAssetIndexAsync(coin: string): Promise<number>;
278
332
  getAssetIndex(coin: string): number;
279
333
  getSzDecimalsAsync(coin: string): Promise<number>;
@@ -300,6 +354,17 @@ export declare class HyperliquidClient {
300
354
  * Useful for long-running strategies that need updated funding rates.
301
355
  */
302
356
  invalidateMetaCache(): void;
357
+ /** Join an allDexsAssetCtxs WebSocket payload with the cached static universes. */
358
+ fundingRatesFromWs(ctxs: ReadonlyArray<[
359
+ string,
360
+ ReadonlyArray<{
361
+ funding?: string | number | null;
362
+ premium?: string | number | null;
363
+ }>
364
+ ]>): Map<string, {
365
+ rate: number;
366
+ premium: number;
367
+ }>;
303
368
  /**
304
369
  * Get all loaded asset names (main + HIP-3)
305
370
  */