openbroker 1.9.2 → 1.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/SKILL.md +49 -0
- package/dist/auto/cli.js +3 -0
- package/dist/auto/examples/dca.d.ts +2 -1
- package/dist/auto/examples/dca.d.ts.map +1 -1
- package/dist/auto/examples/dca.js +19 -1
- package/dist/auto/examples/funding-arb.d.ts +2 -1
- package/dist/auto/examples/funding-arb.d.ts.map +1 -1
- package/dist/auto/examples/funding-arb.js +19 -2
- package/dist/auto/examples/grid.d.ts +2 -1
- package/dist/auto/examples/grid.d.ts.map +1 -1
- package/dist/auto/examples/grid.js +18 -2
- package/dist/auto/examples/mm-maker.d.ts +2 -1
- package/dist/auto/examples/mm-maker.d.ts.map +1 -1
- package/dist/auto/examples/mm-maker.js +18 -2
- package/dist/auto/examples/mm-spread.d.ts +2 -1
- package/dist/auto/examples/mm-spread.d.ts.map +1 -1
- package/dist/auto/examples/mm-spread.js +18 -2
- package/dist/auto/examples/price-alert.d.ts +2 -1
- package/dist/auto/examples/price-alert.d.ts.map +1 -1
- package/dist/auto/examples/price-alert.js +1 -0
- package/dist/auto/guardrails.d.ts +19 -0
- package/dist/auto/guardrails.d.ts.map +1 -0
- package/dist/auto/guardrails.js +575 -0
- package/dist/auto/guardrails.test.d.ts +2 -0
- package/dist/auto/guardrails.test.d.ts.map +1 -0
- package/dist/auto/guardrails.test.js +173 -0
- package/dist/auto/loader.d.ts +3 -3
- package/dist/auto/loader.d.ts.map +1 -1
- package/dist/auto/loader.js +25 -3
- package/dist/auto/runtime.d.ts.map +1 -1
- package/dist/auto/runtime.js +38 -20
- package/dist/auto/types.d.ts +43 -0
- package/dist/auto/types.d.ts.map +1 -1
- package/dist/lib.d.ts +2 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/package.json +4 -3
- package/scripts/auto/cli.ts +3 -0
- package/scripts/auto/examples/dca.ts +21 -2
- package/scripts/auto/examples/funding-arb.ts +21 -3
- package/scripts/auto/examples/grid.ts +20 -3
- package/scripts/auto/examples/mm-maker.ts +20 -3
- package/scripts/auto/examples/mm-spread.ts +20 -3
- package/scripts/auto/examples/price-alert.ts +3 -1
- package/scripts/auto/guardrails.test.ts +227 -0
- package/scripts/auto/guardrails.ts +700 -0
- package/scripts/auto/loader.ts +41 -4
- package/scripts/auto/runtime.ts +38 -22
- package/scripts/auto/types.ts +54 -0
- package/scripts/lib.ts +10 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import { CLIENT_WRITE_METHODS, GuardrailViolation, createGuardrailedClient, validateAutomationGuardrails, } from './guardrails.js';
|
|
4
|
+
import { listExamples, loadAutomation } from './loader.js';
|
|
5
|
+
const logger = {
|
|
6
|
+
info() { },
|
|
7
|
+
warn() { },
|
|
8
|
+
error() { },
|
|
9
|
+
debug() { },
|
|
10
|
+
};
|
|
11
|
+
function tradingPolicy(overrides = {}) {
|
|
12
|
+
return {
|
|
13
|
+
mode: 'trading',
|
|
14
|
+
allowedMarkets: ['ETH'],
|
|
15
|
+
maxOrderUsd: 1_000,
|
|
16
|
+
maxPositionUsd: 2_000,
|
|
17
|
+
maxTotalExposureUsd: 5_000,
|
|
18
|
+
maxLeverage: 2,
|
|
19
|
+
maxMarginUsedPct: 50,
|
|
20
|
+
maxOpenOrders: 10,
|
|
21
|
+
maxOrdersPerMinute: 10,
|
|
22
|
+
maxSlippageBps: 40,
|
|
23
|
+
allowMarketOrders: true,
|
|
24
|
+
allowAccountWideCancel: false,
|
|
25
|
+
...overrides,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function mockClient(options = {}) {
|
|
29
|
+
const calls = [];
|
|
30
|
+
const client = {
|
|
31
|
+
address: '0x0000000000000000000000000000000000000001',
|
|
32
|
+
walletAddress: '0x0000000000000000000000000000000000000002',
|
|
33
|
+
isApiWallet: true,
|
|
34
|
+
async getUserStateAll() {
|
|
35
|
+
return {
|
|
36
|
+
assetPositions: (options.positions ?? []).map((position) => ({
|
|
37
|
+
position: {
|
|
38
|
+
coin: position.coin,
|
|
39
|
+
szi: String(position.size),
|
|
40
|
+
positionValue: String(Math.abs(position.size * position.price)),
|
|
41
|
+
leverage: { type: 'cross', value: position.leverage ?? 1 },
|
|
42
|
+
},
|
|
43
|
+
})),
|
|
44
|
+
marginSummary: { accountValue: '10000', totalMarginUsed: '0' },
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
async getAllMids() { return { ETH: '2000', BTC: '50000' }; },
|
|
48
|
+
async getOpenOrders() { return []; },
|
|
49
|
+
async getSpotBalances() { return { balances: options.spotBalances ?? [] }; },
|
|
50
|
+
async getSpotMetaAndAssetCtxs() {
|
|
51
|
+
return options.spotData ?? { meta: { tokens: [], universe: [] }, assetCtxs: [] };
|
|
52
|
+
},
|
|
53
|
+
resolveOutcomeRef() {
|
|
54
|
+
return { outcome: 1, side: 0, encoding: 10, coin: '#10', tokenName: '+10', assetId: 100000010 };
|
|
55
|
+
},
|
|
56
|
+
async marketOrder(...args) {
|
|
57
|
+
calls.push({ method: 'marketOrder', args });
|
|
58
|
+
return { status: 'ok' };
|
|
59
|
+
},
|
|
60
|
+
async limitOrder(...args) {
|
|
61
|
+
calls.push({ method: 'limitOrder', args });
|
|
62
|
+
return { status: 'ok' };
|
|
63
|
+
},
|
|
64
|
+
async bulkOrder(...args) {
|
|
65
|
+
calls.push({ method: 'bulkOrder', args });
|
|
66
|
+
return { status: 'ok' };
|
|
67
|
+
},
|
|
68
|
+
async spotLimitOrder(...args) {
|
|
69
|
+
calls.push({ method: 'spotLimitOrder', args });
|
|
70
|
+
return { status: 'ok' };
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
return { client, calls };
|
|
74
|
+
}
|
|
75
|
+
test('guardrail schema rejects missing and internally inconsistent limits', () => {
|
|
76
|
+
assert.throws(() => validateAutomationGuardrails({ mode: 'trading' }), /allowedMarkets/);
|
|
77
|
+
assert.throws(() => validateAutomationGuardrails(tradingPolicy({ maxOrderUsd: 3_000 })), /maxOrderUsd.*maxPositionUsd/);
|
|
78
|
+
assert.deepEqual(validateAutomationGuardrails({ mode: 'read-only' }), { mode: 'read-only' });
|
|
79
|
+
});
|
|
80
|
+
test('all client write families are included in the enforcement boundary', () => {
|
|
81
|
+
for (const method of [
|
|
82
|
+
'bulkOrder', 'bulkCancel', 'scheduleCancel',
|
|
83
|
+
'outcomeOrder', 'outcomeMarketOrder', 'outcomeLimitOrder',
|
|
84
|
+
]) {
|
|
85
|
+
assert.equal(CLIENT_WRITE_METHODS.has(method), true, `${method} must be guarded`);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
test('every bundled example exports a valid guardrail policy', async () => {
|
|
89
|
+
for (const example of listExamples()) {
|
|
90
|
+
const loaded = await loadAutomation(example.path, { config: {} });
|
|
91
|
+
assert.ok(loaded.guardrails.mode === 'read-only' || loaded.guardrails.mode === 'trading');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
test('read-only policy blocks every write before it reaches the client', async () => {
|
|
95
|
+
const { client, calls } = mockClient();
|
|
96
|
+
const guarded = createGuardrailedClient(client, {
|
|
97
|
+
policy: { mode: 'read-only' },
|
|
98
|
+
rawClient: client,
|
|
99
|
+
log: logger,
|
|
100
|
+
});
|
|
101
|
+
await assert.rejects(guarded.bulkOrder([{ coin: 'ETH', isBuy: true, size: 0.1, price: 2000 }]), (error) => error instanceof GuardrailViolation && error.code === 'read-only');
|
|
102
|
+
assert.equal(calls.length, 0);
|
|
103
|
+
});
|
|
104
|
+
test('trading policy blocks disallowed markets, missing leverage, and oversized orders', async () => {
|
|
105
|
+
const { client, calls } = mockClient();
|
|
106
|
+
const guarded = createGuardrailedClient(client, {
|
|
107
|
+
policy: tradingPolicy(),
|
|
108
|
+
rawClient: client,
|
|
109
|
+
log: logger,
|
|
110
|
+
});
|
|
111
|
+
await assert.rejects(guarded.limitOrder('BTC', true, 0.01, 50_000, 'Gtc', false, 1), (error) => error instanceof GuardrailViolation && error.code === 'market-not-allowed');
|
|
112
|
+
await assert.rejects(guarded.limitOrder('ETH', true, 0.1, 2_000), (error) => error instanceof GuardrailViolation && error.code === 'leverage-required');
|
|
113
|
+
await assert.rejects(guarded.limitOrder('ETH', true, 0.6, 2_000, 'Gtc', false, 1), (error) => error instanceof GuardrailViolation && error.code === 'order-notional');
|
|
114
|
+
assert.equal(calls.length, 0);
|
|
115
|
+
});
|
|
116
|
+
test('valid market orders execute with runtime-capped slippage', async () => {
|
|
117
|
+
const { client, calls } = mockClient();
|
|
118
|
+
const guarded = createGuardrailedClient(client, {
|
|
119
|
+
policy: tradingPolicy(),
|
|
120
|
+
rawClient: client,
|
|
121
|
+
log: logger,
|
|
122
|
+
});
|
|
123
|
+
await guarded.marketOrder('ETH', true, 0.1, undefined, 1);
|
|
124
|
+
assert.equal(calls.length, 1);
|
|
125
|
+
assert.deepEqual(calls[0], {
|
|
126
|
+
method: 'marketOrder',
|
|
127
|
+
args: ['ETH', true, 0.1, 40, 1],
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
test('account-wide exposure is checked while genuine reductions remain available above caps', async () => {
|
|
131
|
+
const exposed = mockClient({ positions: [{ coin: 'BTC', size: 0.1, price: 50_000 }] });
|
|
132
|
+
const exposureGuarded = createGuardrailedClient(exposed.client, {
|
|
133
|
+
policy: tradingPolicy({ maxTotalExposureUsd: 5_100 }),
|
|
134
|
+
rawClient: exposed.client,
|
|
135
|
+
log: logger,
|
|
136
|
+
});
|
|
137
|
+
await assert.rejects(exposureGuarded.limitOrder('ETH', true, 0.1, 2_000, 'Gtc', false, 1), (error) => error instanceof GuardrailViolation && error.code === 'total-exposure');
|
|
138
|
+
const reducing = mockClient({ positions: [{ coin: 'ETH', size: 1, price: 2_000 }] });
|
|
139
|
+
const reductionGuarded = createGuardrailedClient(reducing.client, {
|
|
140
|
+
policy: tradingPolicy({ maxPositionUsd: 1_000, maxTotalExposureUsd: 1_000 }),
|
|
141
|
+
rawClient: reducing.client,
|
|
142
|
+
log: logger,
|
|
143
|
+
});
|
|
144
|
+
await reductionGuarded.marketOrder('ETH', false, 0.1);
|
|
145
|
+
assert.equal(reducing.calls.length, 1);
|
|
146
|
+
});
|
|
147
|
+
test('spot exposure joins market contexts by pair identifier instead of array position', async () => {
|
|
148
|
+
const { client, calls } = mockClient({
|
|
149
|
+
spotBalances: [{ coin: 'HYPE', total: '3' }],
|
|
150
|
+
spotData: {
|
|
151
|
+
meta: {
|
|
152
|
+
tokens: [{ index: 0, name: 'USDC' }, { index: 1, name: 'HYPE' }],
|
|
153
|
+
universe: [{ name: '@107', tokens: [1, 0] }],
|
|
154
|
+
},
|
|
155
|
+
assetCtxs: [
|
|
156
|
+
{ coin: '@999', midPx: '99999', markPx: '99999' },
|
|
157
|
+
{ coin: '@107', midPx: '62.5', markPx: '62.5' },
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
const guarded = createGuardrailedClient(client, {
|
|
162
|
+
policy: tradingPolicy({
|
|
163
|
+
allowedMarkets: ['spot:HYPE'],
|
|
164
|
+
maxOrderUsd: 100,
|
|
165
|
+
maxPositionUsd: 500,
|
|
166
|
+
maxTotalExposureUsd: 500,
|
|
167
|
+
}),
|
|
168
|
+
rawClient: client,
|
|
169
|
+
log: logger,
|
|
170
|
+
});
|
|
171
|
+
await guarded.spotLimitOrder('HYPE', true, 0.1, 62.5, 'Gtc');
|
|
172
|
+
assert.equal(calls.length, 1);
|
|
173
|
+
});
|
package/dist/auto/loader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AutomationConfig, AutomationGuardrailContext, LoadedAutomation } from './types.js';
|
|
2
2
|
/** Resolve a script path from a name or path */
|
|
3
3
|
export declare function resolveScriptPath(nameOrPath: string): string;
|
|
4
4
|
/** Resolve a bundled example by name */
|
|
@@ -10,8 +10,8 @@ export declare function listExamples(): Array<{
|
|
|
10
10
|
}>;
|
|
11
11
|
/** Load config metadata from all bundled examples */
|
|
12
12
|
export declare function loadExampleConfigs(): Promise<Record<string, AutomationConfig>>;
|
|
13
|
-
/** Load an automation module and validate
|
|
14
|
-
export declare function loadAutomation(scriptPath: string): Promise<
|
|
13
|
+
/** Load an automation module and validate its factory plus required guardrails export. */
|
|
14
|
+
export declare function loadAutomation(scriptPath: string, context?: AutomationGuardrailContext): Promise<LoadedAutomation>;
|
|
15
15
|
/** List available automation scripts in ~/.openbroker/automations/ */
|
|
16
16
|
export declare function listAutomations(): Array<{
|
|
17
17
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../scripts/auto/loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../scripts/auto/loader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAEV,gBAAgB,EAChB,0BAA0B,EAE1B,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAQpB,gDAAgD;AAChD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA2B5D;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED,uCAAuC;AACvC,wBAAgB,YAAY,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CASpE;AAED,qDAAqD;AACrD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAiBpF;AAmDD,0FAA0F;AAC1F,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,0BAA2C,GACnD,OAAO,CAAC,gBAAgB,CAAC,CA0B3B;AAED,sEAAsE;AACtE,wBAAgB,eAAe,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CASvE;AAED,8CAA8C;AAC9C,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
|
package/dist/auto/loader.js
CHANGED
|
@@ -3,6 +3,7 @@ import { existsSync, readdirSync, mkdirSync } from 'fs';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import { resolveAutomationGuardrails } from './guardrails.js';
|
|
6
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
8
|
const __dirname = path.dirname(__filename);
|
|
8
9
|
const AUTOMATIONS_DIR = path.join(os.homedir(), '.openbroker', 'automations');
|
|
@@ -98,8 +99,21 @@ function resolveAutomationConfig(mod) {
|
|
|
98
99
|
}
|
|
99
100
|
return null;
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
function resolveGuardrailsExport(mod) {
|
|
103
|
+
const candidates = [
|
|
104
|
+
mod.guardrails,
|
|
105
|
+
mod.default?.guardrails,
|
|
106
|
+
mod["module.exports"]?.guardrails,
|
|
107
|
+
];
|
|
108
|
+
for (const candidate of candidates) {
|
|
109
|
+
if (candidate && (typeof candidate === 'object' || typeof candidate === 'function')) {
|
|
110
|
+
return candidate;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
/** Load an automation module and validate its factory plus required guardrails export. */
|
|
116
|
+
export async function loadAutomation(scriptPath, context = { config: {} }) {
|
|
103
117
|
const absolutePath = path.resolve(scriptPath);
|
|
104
118
|
// Dynamic import — tsx handles TypeScript transpilation
|
|
105
119
|
const mod = await import(absolutePath);
|
|
@@ -108,7 +122,15 @@ export async function loadAutomation(scriptPath) {
|
|
|
108
122
|
throw new Error(`Automation script must export a default function.\n` +
|
|
109
123
|
`Got: ${typeof factory} from ${scriptPath}`);
|
|
110
124
|
}
|
|
111
|
-
|
|
125
|
+
const guardrailsExport = resolveGuardrailsExport(mod);
|
|
126
|
+
if (!guardrailsExport) {
|
|
127
|
+
throw new Error(`Automation script must export "guardrails".\n` +
|
|
128
|
+
`Use { mode: "read-only" } for monitoring-only scripts or a validated trading policy.`);
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
factory: factory,
|
|
132
|
+
guardrails: resolveAutomationGuardrails(guardrailsExport, context),
|
|
133
|
+
};
|
|
112
134
|
}
|
|
113
135
|
/** List available automation scripts in ~/.openbroker/automations/ */
|
|
114
136
|
export function listAutomations() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../scripts/auto/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../scripts/auto/runtime.ts"],"names":[],"mappings":"AAgBA,OAAO,EAA4C,wBAAwB,IAAI,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG5H,OAAO,KAAK,EAYV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAqYpB,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAKD,wBAAgB,qBAAqB,IAAI,iBAAiB,EAAE,CAE3D;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAEvE;AAED,8EAA8E;AAC9E,OAAO,EAAE,qBAAqB,IAAI,wBAAwB,EAAE,CAAC;AAE7D,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAijBzF"}
|
package/dist/auto/runtime.js
CHANGED
|
@@ -8,6 +8,7 @@ import { roundPrice, roundSize, sleep, normalizeCoin, formatUsd, formatPercent,
|
|
|
8
8
|
import { WebSocketManager } from '../core/ws.js';
|
|
9
9
|
import { AutomationEventBus } from './events.js';
|
|
10
10
|
import { loadAutomation } from './loader.js';
|
|
11
|
+
import { CLIENT_WRITE_METHODS, createGuardrailedClient } from './guardrails.js';
|
|
11
12
|
import { registerAutomation, unregisterAutomation, getRegisteredAutomations as getRegisteredFromFile } from './registry.js';
|
|
12
13
|
import { createAutomationAudit, toSerializable } from './audit.js';
|
|
13
14
|
import { startKeepAwake } from './keep-awake.js';
|
|
@@ -74,12 +75,6 @@ function fanOutAgentAction(observers, action, status, details, txHash) {
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
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
78
|
function createState(id) {
|
|
84
79
|
mkdirSync(STATE_DIR, { recursive: true });
|
|
85
80
|
const stateFile = path.join(STATE_DIR, `${id}.json`);
|
|
@@ -157,18 +152,11 @@ function createLogger(id, verbose, audit) {
|
|
|
157
152
|
};
|
|
158
153
|
}
|
|
159
154
|
// ── 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
155
|
function createDryClient(client, log) {
|
|
168
156
|
return new Proxy(client, {
|
|
169
157
|
get(target, prop, receiver) {
|
|
170
158
|
const value = Reflect.get(target, prop, receiver);
|
|
171
|
-
if (typeof prop === 'string' &&
|
|
159
|
+
if (typeof prop === 'string' && CLIENT_WRITE_METHODS.has(prop) && typeof value === 'function') {
|
|
172
160
|
return (...args) => {
|
|
173
161
|
log.info(`[DRY] ${prop}(${args.map(a => JSON.stringify(a)).join(', ')})`);
|
|
174
162
|
return Promise.resolve({ status: 'ok', response: { type: 'dry_run' } });
|
|
@@ -182,7 +170,7 @@ function createAuditedClient(client, audit, dryRun, observers) {
|
|
|
182
170
|
return new Proxy(client, {
|
|
183
171
|
get(target, prop, receiver) {
|
|
184
172
|
const value = Reflect.get(target, prop, receiver);
|
|
185
|
-
if (typeof prop === 'string' &&
|
|
173
|
+
if (typeof prop === 'string' && CLIENT_WRITE_METHODS.has(prop) && typeof value === 'function') {
|
|
186
174
|
return async (...args) => {
|
|
187
175
|
const actionId = `${prop}:${Date.now()}:${Math.random().toString(16).slice(2)}`;
|
|
188
176
|
audit.recordAction({
|
|
@@ -396,8 +384,39 @@ export async function startAutomation(options) {
|
|
|
396
384
|
}
|
|
397
385
|
}
|
|
398
386
|
const observers = await loadConventionObservers(log);
|
|
387
|
+
let loaded;
|
|
388
|
+
try {
|
|
389
|
+
log.info(`Loading automation: ${scriptPath}`);
|
|
390
|
+
loaded = await loadAutomation(scriptPath, { config: stateController.snapshot() });
|
|
391
|
+
}
|
|
392
|
+
catch (err) {
|
|
393
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
394
|
+
audit.recordError('guardrail_validation', error);
|
|
395
|
+
await audit.stop({
|
|
396
|
+
status: 'error',
|
|
397
|
+
stopReason: 'guardrail_validation_error',
|
|
398
|
+
pollCount: 0,
|
|
399
|
+
eventsEmitted: 0,
|
|
400
|
+
});
|
|
401
|
+
keepAwake?.stop();
|
|
402
|
+
throw error;
|
|
403
|
+
}
|
|
404
|
+
audit.recordNote('guardrails', loaded.guardrails);
|
|
399
405
|
const baseClient = dryRun ? createDryClient(rawClient, log) : rawClient;
|
|
400
|
-
const
|
|
406
|
+
const guardedClient = createGuardrailedClient(baseClient, {
|
|
407
|
+
policy: loaded.guardrails,
|
|
408
|
+
rawClient,
|
|
409
|
+
log,
|
|
410
|
+
onViolation: (error, method, args) => {
|
|
411
|
+
audit.recordNote('guardrail_block', {
|
|
412
|
+
code: error.code,
|
|
413
|
+
message: error.message,
|
|
414
|
+
method,
|
|
415
|
+
args: toSerializable(args),
|
|
416
|
+
});
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
const client = createAuditedClient(guardedClient, audit, dryRun, observers);
|
|
401
420
|
const startHooks = [];
|
|
402
421
|
const stopHooks = [];
|
|
403
422
|
const errorHooks = [];
|
|
@@ -428,12 +447,11 @@ export async function startAutomation(options) {
|
|
|
428
447
|
audit: auditApi,
|
|
429
448
|
id,
|
|
430
449
|
dryRun,
|
|
450
|
+
guardrails: loaded.guardrails,
|
|
431
451
|
};
|
|
432
452
|
try {
|
|
433
|
-
//
|
|
434
|
-
|
|
435
|
-
const factory = await loadAutomation(scriptPath);
|
|
436
|
-
await factory(api);
|
|
453
|
+
// Execute the already validated factory function (registers handlers).
|
|
454
|
+
await loaded.factory(api);
|
|
437
455
|
// Call onStart hooks
|
|
438
456
|
for (const hook of startHooks) {
|
|
439
457
|
try {
|
package/dist/auto/types.d.ts
CHANGED
|
@@ -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';
|
|
@@ -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>;
|
package/dist/auto/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../scripts/auto/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE7E,sDAAsD;AACtD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAC/C;AAID,MAAM,MAAM,mBAAmB,GAC3B,MAAM,GACN,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,cAAc,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3F,eAAe,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5F,eAAe,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,gBAAgB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACzF,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACjG,cAAc,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9E;;;;;;;;;;;OAWG;IACH,YAAY,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IACF,kGAAkG;IAClG,YAAY,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,2EAA2E;IAC3E,WAAW,EAAE;QACX,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,sBAAsB,EAAE,MAAM,CAAC;KAChC,CAAC;CACH;AAED,MAAM,MAAM,sBAAsB,CAAC,CAAC,SAAS,mBAAmB,IAC9D,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAIhE,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC/D,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAC9C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9C,6DAA6D;IAC7D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC3E;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7E,aAAa,CAAC,CACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,GAAG,OAAO,EAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAAC;CACT;AAID,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,KAAK,GAAG,gBAAgB,CAAC;IACpC,iFAAiF;IACjF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,MAAM,EAAE,iBAAiB,CAAC;IAE1B,sCAAsC;IACtC,KAAK,EAAE;QACL,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;QAC5E,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;QACxD,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACrC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;QACxC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;QAC/C,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;QACrE,oBAAoB,EAAE,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,KAAK,MAAM,CAAC;KAC/D,CAAC;IAEF,0CAA0C;IAC1C,EAAE,CAAC,CAAC,SAAS,mBAAmB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAEtF,4EAA4E;IAC5E,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAErE,kEAAkE;IAClE,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAEnD,iFAAiF;IACjF,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAElD,+FAA+F;IAC/F,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAE/D;;;;;;;;OAQG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAErE,gEAAgE;IAChE,KAAK,EAAE,eAAe,CAAC;IAEvB,wBAAwB;IACxB,GAAG,EAAE,gBAAgB,CAAC;IAEtB,2EAA2E;IAC3E,KAAK,EAAE,eAAe,CAAC;IAEvB,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IAEX,oEAAoE;IACpE,MAAM,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../scripts/auto/types.ts"],"names":[],"mappings":"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"}
|
package/dist/lib.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export type { ChaseOptions, ChaseResult } from './operations/chase.js';
|
|
|
11
11
|
export { startAutomation, getRunningAutomations, getAutomation, getRegisteredAutomations, } from './auto/runtime.js';
|
|
12
12
|
export type { RuntimeOptions } from './auto/runtime.js';
|
|
13
13
|
export { resolveScriptPath, resolveExamplePath, listAutomations, listExamples, loadExampleConfigs, ensureAutomationsDir, loadAutomation, } from './auto/loader.js';
|
|
14
|
+
export { GuardrailViolation, CLIENT_WRITE_METHODS, canonicalMarket, validateAutomationGuardrails, resolveAutomationGuardrails, createGuardrailedClient, } from './auto/guardrails.js';
|
|
15
|
+
export type { GuardrailedClientOptions } from './auto/guardrails.js';
|
|
14
16
|
export { registerAutomation, unregisterAutomation, cleanRegistry, getAutomationsToRestart, markAutomationError, } from './auto/registry.js';
|
|
15
17
|
export type * from './auto/types.js';
|
|
16
18
|
//# sourceMappingURL=lib.d.ts.map
|
package/dist/lib.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../scripts/lib.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,iBAAiB,EACjB,SAAS,GACV,MAAM,kBAAkB,CAAC;AAK1B,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE5E,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,UAAU,EACV,SAAS,EACT,KAAK,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,WAAW,EACX,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,mBAAmB,iBAAiB,CAAC;AAIrC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7E,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIvE,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,mBAAmB,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../scripts/lib.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,iBAAiB,EACjB,SAAS,GACV,MAAM,kBAAkB,CAAC;AAK1B,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE5E,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,UAAU,EACV,SAAS,EACT,KAAK,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,WAAW,EACX,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,mBAAmB,iBAAiB,CAAC;AAIrC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7E,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIvE,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,4BAA4B,EAC5B,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,mBAAmB,iBAAiB,CAAC"}
|
package/dist/lib.js
CHANGED
|
@@ -18,4 +18,5 @@ export { runChase } from './operations/chase.js';
|
|
|
18
18
|
// ── Automation runtime ──────────────────────────────────────────────
|
|
19
19
|
export { startAutomation, getRunningAutomations, getAutomation, getRegisteredAutomations, } from './auto/runtime.js';
|
|
20
20
|
export { resolveScriptPath, resolveExamplePath, listAutomations, listExamples, loadExampleConfigs, ensureAutomationsDir, loadAutomation, } from './auto/loader.js';
|
|
21
|
+
export { GuardrailViolation, CLIENT_WRITE_METHODS, canonicalMarket, validateAutomationGuardrails, resolveAutomationGuardrails, createGuardrailedClient, } from './auto/guardrails.js';
|
|
21
22
|
export { registerAutomation, unregisterAutomation, cleanRegistry, getAutomationsToRestart, markAutomationError, } from './auto/registry.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openbroker",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.3",
|
|
4
4
|
"description": "Hyperliquid trading CLI - execute orders, manage positions, and run trading strategies",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -51,8 +51,9 @@
|
|
|
51
51
|
"funding-scan": "tsx scripts/info/funding-scan.ts",
|
|
52
52
|
"outcomes": "tsx scripts/info/outcomes.ts",
|
|
53
53
|
"build": "tsc",
|
|
54
|
-
"prepublishOnly": "npm run build && npm run test:cli",
|
|
55
|
-
"test:cli": "node --import tsx bin/cli.ts --help"
|
|
54
|
+
"prepublishOnly": "npm run build && npm run test:guardrails && npm run test:cli",
|
|
55
|
+
"test:cli": "node --import tsx bin/cli.ts --help",
|
|
56
|
+
"test:guardrails": "node --import tsx --test scripts/auto/guardrails.test.ts"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
59
|
"@nktkas/hyperliquid": "^0.30.3",
|
package/scripts/auto/cli.ts
CHANGED
|
@@ -50,6 +50,8 @@ Scripts are loaded from:
|
|
|
50
50
|
3. Bundled examples (via --example)
|
|
51
51
|
|
|
52
52
|
Writing an automation:
|
|
53
|
+
export const guardrails = { mode: 'read-only' };
|
|
54
|
+
|
|
53
55
|
export default function(api) {
|
|
54
56
|
api.on('price_change', async ({ coin, changePct }) => {
|
|
55
57
|
api.log.info(\`\${coin} moved \${changePct.toFixed(2)}%\`);
|
|
@@ -207,6 +209,7 @@ function listCommand() {
|
|
|
207
209
|
if (automations.length === 0 && examples.length === 0) {
|
|
208
210
|
console.log('No automations found in ~/.openbroker/automations/');
|
|
209
211
|
console.log('\nCreate a .ts file there with:');
|
|
212
|
+
console.log(" export const guardrails = { mode: 'read-only' };");
|
|
210
213
|
console.log(' export default function(api) { ... }');
|
|
211
214
|
console.log('\nOr run a bundled example: openbroker auto examples');
|
|
212
215
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// DCA (Dollar Cost Averaging) — Buy fixed USD amounts at regular intervals
|
|
2
2
|
|
|
3
|
-
import type { AutomationAPI, AutomationConfig } from '../types.js';
|
|
3
|
+
import type { AutomationAPI, AutomationConfig, AutomationGuardrailContext, AutomationGuardrails } from '../types.js';
|
|
4
4
|
|
|
5
5
|
export const config: AutomationConfig = {
|
|
6
6
|
description: 'Dollar cost averaging — buy fixed USD amounts at regular intervals',
|
|
@@ -12,6 +12,25 @@ export const config: AutomationConfig = {
|
|
|
12
12
|
},
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
export function guardrails({ config: values }: AutomationGuardrailContext): AutomationGuardrails {
|
|
16
|
+
const amount = Number(values.amount ?? 100);
|
|
17
|
+
const count = Number(values.count ?? 24);
|
|
18
|
+
return {
|
|
19
|
+
mode: 'trading',
|
|
20
|
+
allowedMarkets: [String(values.coin ?? 'HYPE')],
|
|
21
|
+
maxOrderUsd: amount * 1.1,
|
|
22
|
+
maxPositionUsd: amount * count * 1.1,
|
|
23
|
+
maxTotalExposureUsd: amount * count * 1.1,
|
|
24
|
+
maxLeverage: 1,
|
|
25
|
+
maxMarginUsedPct: 50,
|
|
26
|
+
maxOpenOrders: 5,
|
|
27
|
+
maxOrdersPerMinute: 5,
|
|
28
|
+
maxSlippageBps: 50,
|
|
29
|
+
allowMarketOrders: true,
|
|
30
|
+
allowAccountWideCancel: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
15
34
|
export default function dca(api: AutomationAPI) {
|
|
16
35
|
const COIN = api.state.get<string>('coin', 'HYPE')!;
|
|
17
36
|
const AMOUNT_USD = api.state.get<number>('amount', 100)!;
|
|
@@ -43,7 +62,7 @@ export default function dca(api: AutomationAPI) {
|
|
|
43
62
|
const size = AMOUNT_USD / price;
|
|
44
63
|
api.log.info(`[${purchased + 1}/${MAX_PURCHASES}] Buying ~$${AMOUNT_USD} of ${COIN} @ $${price.toFixed(2)}`);
|
|
45
64
|
|
|
46
|
-
const response = await api.client.marketOrder(COIN, true, size);
|
|
65
|
+
const response = await api.client.marketOrder(COIN, true, size, undefined, 1);
|
|
47
66
|
if (response.status === 'ok' && response.response && typeof response.response === 'object') {
|
|
48
67
|
const status = response.response.data.statuses[0];
|
|
49
68
|
if (status?.filled) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Funding Arbitrage — Collect funding by positioning opposite to the crowd
|
|
2
2
|
|
|
3
|
-
import type { AutomationAPI, AutomationConfig } from '../types.js';
|
|
3
|
+
import type { AutomationAPI, AutomationConfig, AutomationGuardrailContext, AutomationGuardrails } from '../types.js';
|
|
4
4
|
|
|
5
5
|
export const config: AutomationConfig = {
|
|
6
6
|
description: 'Funding arbitrage — collect funding by positioning opposite to the crowd',
|
|
@@ -13,6 +13,24 @@ export const config: AutomationConfig = {
|
|
|
13
13
|
},
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
export function guardrails({ config: values }: AutomationGuardrailContext): AutomationGuardrails {
|
|
17
|
+
const sizeUsd = Number(values.sizeUsd ?? 5000);
|
|
18
|
+
return {
|
|
19
|
+
mode: 'trading',
|
|
20
|
+
allowedMarkets: [String(values.coin ?? 'HYPE')],
|
|
21
|
+
maxOrderUsd: sizeUsd * 1.1,
|
|
22
|
+
maxPositionUsd: sizeUsd * 1.1,
|
|
23
|
+
maxTotalExposureUsd: sizeUsd * 1.1,
|
|
24
|
+
maxLeverage: 1,
|
|
25
|
+
maxMarginUsedPct: 50,
|
|
26
|
+
maxOpenOrders: 5,
|
|
27
|
+
maxOrdersPerMinute: 4,
|
|
28
|
+
maxSlippageBps: 50,
|
|
29
|
+
allowMarketOrders: true,
|
|
30
|
+
allowAccountWideCancel: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
16
34
|
export default function fundingArb(api: AutomationAPI) {
|
|
17
35
|
const COIN = api.state.get<string>('coin', 'HYPE')!;
|
|
18
36
|
const SIZE_USD = api.state.get<number>('sizeUsd', 5000)!;
|
|
@@ -48,7 +66,7 @@ export default function fundingArb(api: AutomationAPI) {
|
|
|
48
66
|
if (shouldClose) {
|
|
49
67
|
api.log.info(`Funding dropped to ${annualizedPct.toFixed(2)}% (below ${CLOSE_AT}%), closing ${positionSide}`);
|
|
50
68
|
const closeIsBuy = positionSide === 'short';
|
|
51
|
-
await api.client.marketOrder(coin, closeIsBuy, positionSize);
|
|
69
|
+
await api.client.marketOrder(coin, closeIsBuy, positionSize, undefined, 1);
|
|
52
70
|
|
|
53
71
|
inPosition = false;
|
|
54
72
|
api.state.set('inPosition', false);
|
|
@@ -69,7 +87,7 @@ export default function fundingArb(api: AutomationAPI) {
|
|
|
69
87
|
const size = SIZE_USD / price;
|
|
70
88
|
|
|
71
89
|
api.log.info(`Funding at ${annualizedPct.toFixed(2)}% — opening ${side} ${size.toFixed(6)} ${coin}`);
|
|
72
|
-
const response = await api.client.marketOrder(coin, !shouldShort, size);
|
|
90
|
+
const response = await api.client.marketOrder(coin, !shouldShort, size, undefined, 1);
|
|
73
91
|
|
|
74
92
|
if (response.status === 'ok' && response.response && typeof response.response === 'object') {
|
|
75
93
|
const status = response.response.data.statuses[0];
|