@reefclaw/openclaw-plugin 0.1.5 → 0.1.7
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/bridge/gateway/event-parser.d.ts +6 -1
- package/bridge/gateway/event-parser.js +19 -2
- package/bridge/gateway/poller.d.ts +1 -0
- package/bridge/gateway/poller.js +14 -2
- package/bridge/providers/gateway.d.ts +22 -2
- package/bridge/providers/gateway.js +67 -9
- package/ccxt/binance-private.d.ts +21 -0
- package/ccxt/binance-private.js +132 -22
- package/ccxt/public-market-data-api.d.ts +14 -0
- package/ccxt/public-market-data-api.js +15 -1
- package/config/plugin-config-io.d.ts +13 -0
- package/config/plugin-config-io.js +15 -0
- package/config/tool-gate.js +3 -0
- package/exchange-adapter.d.ts +16 -0
- package/index.js +658 -83
- package/ingest/position-auto-capture.d.ts +68 -0
- package/ingest/position-auto-capture.js +321 -23
- package/ingest/position-decisions-client.d.ts +7 -2
- package/ingest/position-decisions-client.js +13 -3
- package/ingest/reconcile-db-vs-exchange.d.ts +39 -1
- package/ingest/reconcile-db-vs-exchange.js +66 -10
- package/lifecycle/trading-operation-lock.d.ts +17 -0
- package/lifecycle/trading-operation-lock.js +14 -0
- package/live/bracket-id.d.ts +2 -3
- package/live/bracket-id.js +22 -9
- package/live/fill-price.d.ts +13 -0
- package/live/fill-price.js +37 -0
- package/live/live-adapter.d.ts +57 -2
- package/live/live-adapter.js +290 -49
- package/live/local-signal-service.js +11 -6
- package/live/local-strategy-evaluator.js +4 -0
- package/live/position-state-store.d.ts +4 -0
- package/live/proposal-decision-listener.d.ts +6 -0
- package/live/proposal-decision-listener.js +4 -0
- package/live/stop-watcher.d.ts +35 -2
- package/live/stop-watcher.js +63 -3
- package/onboarding/runtime.d.ts +19 -0
- package/onboarding/runtime.js +34 -3
- package/openclaw.plugin.json +1 -0
- package/package.json +2 -2
- package/portfolio/reentry-tracker.d.ts +36 -0
- package/portfolio/reentry-tracker.js +127 -0
- package/portfolio/wave9-admission.d.ts +67 -0
- package/portfolio/wave9-admission.js +262 -0
- package/portfolio/wave9-policy.d.ts +36 -0
- package/portfolio/wave9-policy.js +183 -0
- package/signals/conditions/registry.js +61 -2
- package/signals/strategy-adapter.js +17 -7
- package/simulator/exchange-simulator.d.ts +12 -0
- package/simulator/exchange-simulator.js +78 -3
- package/simulator/fill-engine.js +5 -1
- package/simulator/types.d.ts +10 -1
- package/skills/reefclaw/SKILL.md +2 -0
- package/strategy/evaluator.d.ts +3 -0
- package/strategy/evaluator.js +5 -0
- package/tools/assessment-validation.d.ts +23 -0
- package/tools/assessment-validation.js +58 -0
- package/tools/attach-brackets.d.ts +7 -2
- package/tools/attach-brackets.js +201 -0
- package/tools/audit-bracket-protection.js +157 -1
- package/tools/bracket-control.d.ts +12 -0
- package/tools/bracket-control.js +35 -0
- package/tools/cancel-all-orders.d.ts +2 -0
- package/tools/cancel-all-orders.js +4 -1
- package/tools/cancel-order.d.ts +4 -0
- package/tools/cancel-order.js +49 -3
- package/tools/close-position.d.ts +23 -0
- package/tools/close-position.js +286 -13
- package/tools/create-order.d.ts +28 -0
- package/tools/create-order.js +1390 -190
- package/tools/get-analytics.js +2 -2
- package/tools/get-basis.js +2 -2
- package/tools/get-cascade-risk.js +2 -2
- package/tools/get-crypto-metrics.js +14 -4
- package/tools/get-cvd.js +2 -2
- package/tools/get-divergences.js +2 -2
- package/tools/get-funding-context.js +2 -2
- package/tools/get-liquidation-levels.js +2 -2
- package/tools/get-liquidation-pulse.js +2 -2
- package/tools/get-pattern-scan.js +2 -2
- package/tools/get-regime.js +2 -2
- package/tools/get-resting-liquidity.js +2 -2
- package/tools/get-risk-scenario.js +2 -2
- package/tools/get-session-review.js +2 -2
- package/tools/get-setup-detail.js +21 -2
- package/tools/get-signals.js +2 -2
- package/tools/get-sizing.js +2 -2
- package/tools/get-trade-feedback.js +2 -2
- package/tools/get-trade-flow.js +2 -2
- package/tools/get-volume-profile.js +2 -2
- package/tools/get-wave9-status.d.ts +127 -0
- package/tools/get-wave9-status.js +796 -0
- package/tools/intel-api.d.ts +20 -0
- package/tools/intel-api.js +67 -0
- package/tools/intel-cache.d.ts +1 -1
- package/tools/intel-cache.js +20 -5
- package/tools/list-strategies.d.ts +11 -1
- package/tools/list-strategies.js +17 -0
- package/tools/modify-stop.d.ts +4 -0
- package/tools/modify-stop.js +63 -24
- package/tools/modify-target.d.ts +4 -0
- package/tools/modify-target.js +62 -23
- package/tools/scan-pairs.d.ts +4 -0
- package/tools/scan-pairs.js +22 -8
- package/tools/toggle-strategy.js +7 -0
- package/types.d.ts +5 -0
- package/venues/hyperliquid/hl-balance.d.ts +116 -0
- package/venues/hyperliquid/hl-balance.js +145 -0
- package/venues/hyperliquid/hl-bracket-coordinator.d.ts +123 -0
- package/venues/hyperliquid/hl-bracket-coordinator.js +533 -0
- package/venues/hyperliquid/hl-brackets.d.ts +102 -0
- package/venues/hyperliquid/hl-brackets.js +172 -0
- package/venues/hyperliquid/hl-cloid.d.ts +22 -0
- package/venues/hyperliquid/hl-cloid.js +82 -0
- package/venues/hyperliquid/hl-info-cache.d.ts +46 -0
- package/venues/hyperliquid/hl-info-cache.js +125 -0
- package/venues/hyperliquid/hl-live-adapter.d.ts +146 -0
- package/venues/hyperliquid/hl-live-adapter.js +728 -0
- package/venues/hyperliquid/hl-precision.d.ts +61 -0
- package/venues/hyperliquid/hl-precision.js +176 -0
- package/venues/hyperliquid/hl-private.d.ts +88 -0
- package/venues/hyperliquid/hl-private.js +357 -0
- package/venues/hyperliquid/hl-public.d.ts +31 -4
- package/venues/hyperliquid/hl-public.js +163 -12
- package/venues/hyperliquid/hl-rate-gate.d.ts +57 -0
- package/venues/hyperliquid/hl-rate-gate.js +220 -0
- package/venues/hyperliquid/hl-user-stream.d.ts +90 -0
- package/venues/hyperliquid/hl-user-stream.js +220 -0
- package/venues/registry.d.ts +23 -9
- package/venues/registry.js +12 -13
- package/venues/symbols.d.ts +43 -0
- package/venues/symbols.js +107 -0
- package/wave9/live-account-capture.d.ts +67 -0
- package/wave9/live-account-capture.js +435 -0
- package/wave9/live-autonomous-protection.d.ts +39 -0
- package/wave9/live-autonomous-protection.js +112 -0
- package/wave9/live-durable-reconciliation-scheduler.d.ts +33 -0
- package/wave9/live-durable-reconciliation-scheduler.js +115 -0
- package/wave9/live-execution-ledger.d.ts +107 -0
- package/wave9/live-execution-ledger.js +498 -0
- package/wave9/live-position-confirmation.d.ts +18 -0
- package/wave9/live-position-confirmation.js +111 -0
- package/wave9/live-residual-protection.d.ts +18 -0
- package/wave9/live-residual-protection.js +250 -0
- package/wave9/live-startup-reconciliation.d.ts +38 -0
- package/wave9/live-startup-reconciliation.js +454 -0
- package/wave9/live-symbol-ownership.d.ts +20 -0
- package/wave9/live-symbol-ownership.js +132 -0
- package/wave9/paper-admission-guard.d.ts +199 -0
- package/wave9/paper-admission-guard.js +650 -0
- package/wave9/usdm-evidence-provider.d.ts +42 -0
- package/wave9/usdm-evidence-provider.js +133 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** HL minimum order value in USDC. Observed live 2026-07-12 (a $6 order was
|
|
2
|
+
* rejected: "Order must have minimum value of $10"). */
|
|
3
|
+
export declare const HL_MIN_NOTIONAL_USD = 10;
|
|
4
|
+
export type RoundDirection = 'down' | 'up';
|
|
5
|
+
/** Count significant figures of a decimal string (leading zeros are not
|
|
6
|
+
* significant; trailing zeros AFTER a decimal point are, but we always emit
|
|
7
|
+
* trimmed strings so they never appear). */
|
|
8
|
+
export declare function countSignificantFigures(value: number): number;
|
|
9
|
+
/** Decimal places of a value (0 for integers). */
|
|
10
|
+
export declare function decimalPlaces(value: number): number;
|
|
11
|
+
export interface HlAssetRules {
|
|
12
|
+
/** Size decimals from `meta.universe[].szDecimals`. */
|
|
13
|
+
szDecimals: number;
|
|
14
|
+
/** Asset index — the `a` field of an order. NEVER hardcode: mainnet and
|
|
15
|
+
* testnet indices differ ([asset-ids]). */
|
|
16
|
+
assetIndex: number;
|
|
17
|
+
maxLeverage?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Is this price acceptable to Hyperliquid as-is? (The exact documented rule —
|
|
20
|
+
* used by tests and as a post-round assertion, never as a substitute for
|
|
21
|
+
* rounding.) */
|
|
22
|
+
export declare function isValidHlPrice(price: number, szDecimals: number): boolean;
|
|
23
|
+
/** Round a price to the nearest HL-legal value in the requested direction.
|
|
24
|
+
*
|
|
25
|
+
* Applies BOTH constraints (≤5 sig figs AND ≤ MAX_DECIMALS−szDecimals decimals),
|
|
26
|
+
* tightest-wins. An integer result is always legal, so the decimal cap can never
|
|
27
|
+
* push a price to an illegal value. */
|
|
28
|
+
export declare function roundHlPrice(price: number, szDecimals: number, dir: RoundDirection): number;
|
|
29
|
+
/** Round an order size DOWN to szDecimals. Always DOWN: rounding a size up can
|
|
30
|
+
* overshoot the position (a reduce-only leg sized above the position is rejected)
|
|
31
|
+
* or exceed the intended risk. */
|
|
32
|
+
export declare function roundHlSize(size: number, szDecimals: number): number;
|
|
33
|
+
export interface HlValidationResult {
|
|
34
|
+
valid: boolean;
|
|
35
|
+
error?: string;
|
|
36
|
+
roundedAmount: number;
|
|
37
|
+
roundedPrice?: number;
|
|
38
|
+
}
|
|
39
|
+
/** Pre-flight validation mirroring `ExchangeInfoCache.validate`'s contract
|
|
40
|
+
* (same shape, same "round then check" order, same dollar-hint error copy) so
|
|
41
|
+
* the adapter's call sites are venue-symmetric.
|
|
42
|
+
*
|
|
43
|
+
* @param side drives passive rounding of a limit price (buy → down, sell → up).
|
|
44
|
+
* @param referencePrice mark/mid — used for the notional check when no limit
|
|
45
|
+
* price is given (market orders). */
|
|
46
|
+
export declare function validateHlOrder(args: {
|
|
47
|
+
amount: number;
|
|
48
|
+
price?: number;
|
|
49
|
+
referencePrice?: number;
|
|
50
|
+
rules: HlAssetRules;
|
|
51
|
+
side: 'buy' | 'sell';
|
|
52
|
+
}): HlValidationResult;
|
|
53
|
+
/** The IOC price bound that emulates a market order (HL has no native market
|
|
54
|
+
* order — plan §3.4). Explicit slippage ALWAYS — ccxt's `defaultSlippage: 0.05`
|
|
55
|
+
* (5%!) is never relied upon. */
|
|
56
|
+
export declare function marketIocPrice(args: {
|
|
57
|
+
referencePrice: number;
|
|
58
|
+
side: 'buy' | 'sell';
|
|
59
|
+
slippagePct: number;
|
|
60
|
+
szDecimals: number;
|
|
61
|
+
}): number;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Hyperliquid price/size precision — the rule, implemented HERE, on strings.
|
|
2
|
+
//
|
|
3
|
+
// ★ WHY NOT CCXT: `priceToPrecision` has a known rounding bug in the [1,10)
|
|
4
|
+
// range (ccxt#26132) and the whole point of a safety floor is that the stop
|
|
5
|
+
// price we compute is the stop price the exchange gets. Plan §5.5: own the math.
|
|
6
|
+
//
|
|
7
|
+
// ★ WHY NOT decimal.js: it would become a runtime dependency of the PUBLISHED
|
|
8
|
+
// plugin package. The rule below only needs exact DECIMAL-STRING manipulation
|
|
9
|
+
// (truncate / count significant figures) — no arithmetic on values — so strings
|
|
10
|
+
// are both exact and dependency-free. Every function takes and returns numbers at
|
|
11
|
+
// the boundary but never rounds through binary floating point.
|
|
12
|
+
//
|
|
13
|
+
// THE RULE (docs, verified 2026-07-11; re-verified live 2026-07-12):
|
|
14
|
+
// PRICE is valid iff
|
|
15
|
+
// - it is an INTEGER (always allowed, regardless of sig figs), OR
|
|
16
|
+
// - it has ≤ 5 significant figures AND ≤ (MAX_DECIMALS − szDecimals) decimals
|
|
17
|
+
// where MAX_DECIMALS = 6 for perps.
|
|
18
|
+
// SIZE is rounded DOWN to szDecimals (from `meta.universe`).
|
|
19
|
+
// MIN NOTIONAL is $10 (observed live: "Order must have minimum value of $10").
|
|
20
|
+
//
|
|
21
|
+
// Rounding direction is explicit at every call site — never "nearest" by default
|
|
22
|
+
// on a protective leg. `passive` semantics: a BUY rounds DOWN, a SELL rounds UP,
|
|
23
|
+
// so a rounded limit never crosses further into the book than intended.
|
|
24
|
+
const MAX_DECIMALS_PERP = 6;
|
|
25
|
+
/** HL minimum order value in USDC. Observed live 2026-07-12 (a $6 order was
|
|
26
|
+
* rejected: "Order must have minimum value of $10"). */
|
|
27
|
+
export const HL_MIN_NOTIONAL_USD = 10;
|
|
28
|
+
/** Split a finite number into its exact decimal string parts, expanding any
|
|
29
|
+
* exponent form ("1e-7") that JS produces for small/large magnitudes — the
|
|
30
|
+
* string rule below must never see an "e". */
|
|
31
|
+
function toPlainDecimalString(value) {
|
|
32
|
+
if (!Number.isFinite(value))
|
|
33
|
+
throw new Error(`not finite: ${value}`);
|
|
34
|
+
// toPrecision(17) is lossless for a double, and never yields exponent form for
|
|
35
|
+
// the magnitudes we trade; Number() re-parses to drop trailing zeros.
|
|
36
|
+
const s = String(value);
|
|
37
|
+
if (!s.includes('e') && !s.includes('E'))
|
|
38
|
+
return s;
|
|
39
|
+
// Exponent form → expand via toFixed with enough decimals (bounded: HL prices
|
|
40
|
+
// never need more than 20 decimals, and sizes are capped by szDecimals).
|
|
41
|
+
return value.toFixed(20).replace(/0+$/, '').replace(/\.$/, '');
|
|
42
|
+
}
|
|
43
|
+
/** Count significant figures of a decimal string (leading zeros are not
|
|
44
|
+
* significant; trailing zeros AFTER a decimal point are, but we always emit
|
|
45
|
+
* trimmed strings so they never appear). */
|
|
46
|
+
export function countSignificantFigures(value) {
|
|
47
|
+
const s = toPlainDecimalString(Math.abs(value));
|
|
48
|
+
const digits = s.replace('.', '').replace(/^0+/, '').replace(/0+$/, '');
|
|
49
|
+
// An integer like 1200 has 2 sig figs by this measure — which is the
|
|
50
|
+
// conservative reading, and integers are unconditionally allowed anyway.
|
|
51
|
+
return digits.length === 0 ? 1 : digits.length;
|
|
52
|
+
}
|
|
53
|
+
/** Decimal places of a value (0 for integers). */
|
|
54
|
+
export function decimalPlaces(value) {
|
|
55
|
+
const s = toPlainDecimalString(Math.abs(value));
|
|
56
|
+
const dot = s.indexOf('.');
|
|
57
|
+
return dot === -1 ? 0 : s.length - dot - 1;
|
|
58
|
+
}
|
|
59
|
+
/** Truncate a decimal string to N decimals, rounding in the requested direction.
|
|
60
|
+
* Exact — no binary float rounding anywhere. */
|
|
61
|
+
function roundDecimals(value, decimals, dir) {
|
|
62
|
+
if (decimals < 0)
|
|
63
|
+
decimals = 0;
|
|
64
|
+
const factor = 10 ** decimals;
|
|
65
|
+
// Work in an integer domain scaled by `factor`; the +/- 1e-9 nudge absorbs the
|
|
66
|
+
// classic 0.1*3 = 0.30000000000000004 representation error WITHOUT changing a
|
|
67
|
+
// value that is genuinely on the boundary.
|
|
68
|
+
const scaled = value * factor;
|
|
69
|
+
const eps = 1e-9;
|
|
70
|
+
const out = dir === 'down' ? Math.floor(scaled + eps) : Math.ceil(scaled - eps);
|
|
71
|
+
return out / factor;
|
|
72
|
+
}
|
|
73
|
+
/** Round a value to at most `sig` significant figures, in the given direction. */
|
|
74
|
+
function roundToSignificantFigures(value, sig, dir) {
|
|
75
|
+
if (value === 0)
|
|
76
|
+
return 0;
|
|
77
|
+
const magnitude = Math.floor(Math.log10(Math.abs(value)));
|
|
78
|
+
// decimals needed so that the value carries exactly `sig` significant figures
|
|
79
|
+
const decimals = sig - 1 - magnitude;
|
|
80
|
+
return roundDecimals(value, Math.max(decimals, 0), dir);
|
|
81
|
+
}
|
|
82
|
+
/** Is this price acceptable to Hyperliquid as-is? (The exact documented rule —
|
|
83
|
+
* used by tests and as a post-round assertion, never as a substitute for
|
|
84
|
+
* rounding.) */
|
|
85
|
+
export function isValidHlPrice(price, szDecimals) {
|
|
86
|
+
if (!Number.isFinite(price) || price <= 0)
|
|
87
|
+
return false;
|
|
88
|
+
if (Number.isInteger(price))
|
|
89
|
+
return true; // integers always allowed
|
|
90
|
+
const maxDecimals = MAX_DECIMALS_PERP - szDecimals;
|
|
91
|
+
return countSignificantFigures(price) <= 5 && decimalPlaces(price) <= maxDecimals;
|
|
92
|
+
}
|
|
93
|
+
/** Round a price to the nearest HL-legal value in the requested direction.
|
|
94
|
+
*
|
|
95
|
+
* Applies BOTH constraints (≤5 sig figs AND ≤ MAX_DECIMALS−szDecimals decimals),
|
|
96
|
+
* tightest-wins. An integer result is always legal, so the decimal cap can never
|
|
97
|
+
* push a price to an illegal value. */
|
|
98
|
+
export function roundHlPrice(price, szDecimals, dir) {
|
|
99
|
+
if (!Number.isFinite(price) || price <= 0) {
|
|
100
|
+
throw new Error(`Invalid HL price: ${price}`);
|
|
101
|
+
}
|
|
102
|
+
const maxDecimals = Math.max(MAX_DECIMALS_PERP - szDecimals, 0);
|
|
103
|
+
// 1) cap significant figures
|
|
104
|
+
let out = roundToSignificantFigures(price, 5, dir);
|
|
105
|
+
// 2) cap decimals (may reduce sig figs further — that stays legal)
|
|
106
|
+
if (decimalPlaces(out) > maxDecimals) {
|
|
107
|
+
out = roundDecimals(out, maxDecimals, dir);
|
|
108
|
+
}
|
|
109
|
+
// A rounded-to-zero price is never legal — fall back to the smallest legal tick.
|
|
110
|
+
if (out <= 0)
|
|
111
|
+
out = 1 / 10 ** maxDecimals;
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
/** Round an order size DOWN to szDecimals. Always DOWN: rounding a size up can
|
|
115
|
+
* overshoot the position (a reduce-only leg sized above the position is rejected)
|
|
116
|
+
* or exceed the intended risk. */
|
|
117
|
+
export function roundHlSize(size, szDecimals) {
|
|
118
|
+
if (!Number.isFinite(size) || size < 0) {
|
|
119
|
+
throw new Error(`Invalid HL size: ${size}`);
|
|
120
|
+
}
|
|
121
|
+
return roundDecimals(size, szDecimals, 'down');
|
|
122
|
+
}
|
|
123
|
+
/** Pre-flight validation mirroring `ExchangeInfoCache.validate`'s contract
|
|
124
|
+
* (same shape, same "round then check" order, same dollar-hint error copy) so
|
|
125
|
+
* the adapter's call sites are venue-symmetric.
|
|
126
|
+
*
|
|
127
|
+
* @param side drives passive rounding of a limit price (buy → down, sell → up).
|
|
128
|
+
* @param referencePrice mark/mid — used for the notional check when no limit
|
|
129
|
+
* price is given (market orders). */
|
|
130
|
+
export function validateHlOrder(args) {
|
|
131
|
+
const { amount, price, referencePrice, rules, side } = args;
|
|
132
|
+
const { szDecimals } = rules;
|
|
133
|
+
const roundedAmount = roundHlSize(amount, szDecimals);
|
|
134
|
+
if (roundedAmount <= 0) {
|
|
135
|
+
return {
|
|
136
|
+
valid: false,
|
|
137
|
+
error: `Amount ${amount} rounds to zero at ${szDecimals} decimals — increase the size`,
|
|
138
|
+
roundedAmount: 0,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
let roundedPrice;
|
|
142
|
+
if (price !== undefined) {
|
|
143
|
+
roundedPrice = roundHlPrice(price, szDecimals, side === 'buy' ? 'down' : 'up');
|
|
144
|
+
}
|
|
145
|
+
const notionalPrice = roundedPrice ?? referencePrice;
|
|
146
|
+
if (notionalPrice !== undefined && notionalPrice > 0) {
|
|
147
|
+
const notional = roundedAmount * notionalPrice;
|
|
148
|
+
if (notional < HL_MIN_NOTIONAL_USD) {
|
|
149
|
+
const minAmount = HL_MIN_NOTIONAL_USD / notionalPrice;
|
|
150
|
+
return {
|
|
151
|
+
valid: false,
|
|
152
|
+
// Same dollar-hint shape the Binance path uses — the agent gets an
|
|
153
|
+
// actionable number, not a rule citation.
|
|
154
|
+
error: `Order value $${notional.toFixed(2)} is below Hyperliquid's $${HL_MIN_NOTIONAL_USD} minimum. ` +
|
|
155
|
+
`Increase size to at least ${minAmount.toFixed(szDecimals + 1)} (≈$${HL_MIN_NOTIONAL_USD}).`,
|
|
156
|
+
roundedAmount,
|
|
157
|
+
roundedPrice,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return { valid: true, roundedAmount, roundedPrice };
|
|
162
|
+
}
|
|
163
|
+
/** The IOC price bound that emulates a market order (HL has no native market
|
|
164
|
+
* order — plan §3.4). Explicit slippage ALWAYS — ccxt's `defaultSlippage: 0.05`
|
|
165
|
+
* (5%!) is never relied upon. */
|
|
166
|
+
export function marketIocPrice(args) {
|
|
167
|
+
const { referencePrice, side, slippagePct, szDecimals } = args;
|
|
168
|
+
if (!Number.isFinite(referencePrice) || referencePrice <= 0) {
|
|
169
|
+
throw new Error(`marketIocPrice needs a positive reference price, got ${referencePrice}`);
|
|
170
|
+
}
|
|
171
|
+
const slip = Math.min(Math.max(slippagePct, 0), 0.02); // hard clamp ≤2%
|
|
172
|
+
const raw = side === 'buy' ? referencePrice * (1 + slip) : referencePrice * (1 - slip);
|
|
173
|
+
// Round the bound OUTWARD (buy up / sell down) so rounding never makes the
|
|
174
|
+
// order less marketable than intended.
|
|
175
|
+
return roundHlPrice(raw, szDecimals, side === 'buy' ? 'up' : 'down');
|
|
176
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { CcxtOrder, CcxtPosition, CcxtBalance } from '../../types.js';
|
|
2
|
+
export interface HlCredentials {
|
|
3
|
+
/** MASTER account address (0x…). Queries always use this — an agent wallet
|
|
4
|
+
* holds no balance and no positions (learned the hard way 2026-07-12). */
|
|
5
|
+
walletAddress: string;
|
|
6
|
+
/** AGENT (API) wallet private key — signs, never holds funds. */
|
|
7
|
+
agentPrivateKey: string;
|
|
8
|
+
testnet?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** The CCXT options that MUST be present on every authed HL client. Exported so
|
|
11
|
+
* `hl-private.test.ts` can assert them — if a future ccxt bump changes the
|
|
12
|
+
* option names, the test fails rather than the users paying a silent 1bp. */
|
|
13
|
+
export declare const HL_REQUIRED_OPTIONS: {
|
|
14
|
+
readonly builderFee: false;
|
|
15
|
+
readonly refSet: true;
|
|
16
|
+
};
|
|
17
|
+
export interface HlTriggerParams {
|
|
18
|
+
/** Trigger price (fires on MARK — HL has no workingType choice). */
|
|
19
|
+
triggerPrice: number;
|
|
20
|
+
/** 'sl' | 'tp' — HL's own naming. */
|
|
21
|
+
tpsl: 'sl' | 'tp';
|
|
22
|
+
reduceOnly: true;
|
|
23
|
+
cloid?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface HlOrderRequest {
|
|
26
|
+
symbol: string;
|
|
27
|
+
side: 'buy' | 'sell';
|
|
28
|
+
/** 'market' is emulated: an IOC limit at `price` (the caller must have applied
|
|
29
|
+
* the slippage bound via hl-precision.marketIocPrice). */
|
|
30
|
+
type: 'market' | 'limit';
|
|
31
|
+
amount: number;
|
|
32
|
+
price: number;
|
|
33
|
+
reduceOnly?: boolean;
|
|
34
|
+
postOnly?: boolean;
|
|
35
|
+
cloid?: string;
|
|
36
|
+
trigger?: {
|
|
37
|
+
triggerPrice: number;
|
|
38
|
+
tpsl: 'sl' | 'tp';
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export declare class HyperliquidPrivateApi {
|
|
42
|
+
private readonly creds;
|
|
43
|
+
private readonly exchange;
|
|
44
|
+
private readonly mutex;
|
|
45
|
+
private marketsLoaded;
|
|
46
|
+
constructor(creds: HlCredentials);
|
|
47
|
+
/** Exposed for the options-pin test + diagnostics. */
|
|
48
|
+
getExchange(): any;
|
|
49
|
+
loadMarkets(): Promise<boolean>;
|
|
50
|
+
/** Positions for the MASTER account. `null` = fetch failed (state unknown);
|
|
51
|
+
* `[]` = the exchange confirmed flat. */
|
|
52
|
+
fetchPositions(symbol?: string): Promise<CcxtPosition[] | null>;
|
|
53
|
+
/** Open orders INCLUDING trigger/TPSL legs. CCXT's HL `fetchOpenOrders`
|
|
54
|
+
* defaults to `frontendOpenOrders`, which is the only endpoint that returns
|
|
55
|
+
* trigger orders (plan §3.6) — the analog of Binance's merged algo endpoints. */
|
|
56
|
+
fetchOpenOrders(symbol?: string): Promise<CcxtOrder[] | null>;
|
|
57
|
+
fetchBalance(): Promise<CcxtBalance | null>;
|
|
58
|
+
/** Per-order status — the liveness resolver's REST tier (Tier 2 of the
|
|
59
|
+
* 3-tier rule). Weight 2. `null` = lookup FAILED (unknown), which callers
|
|
60
|
+
* must treat as "do not act", NOT as "gone". */
|
|
61
|
+
fetchOrder(orderId: string, symbol?: string): Promise<CcxtOrder | null>;
|
|
62
|
+
/** Own fills. WS is the authoritative ingress (plan + the audit-trail rule);
|
|
63
|
+
* this is the gap-fill/truth-check path. NOTE: only the 10,000 most recent
|
|
64
|
+
* fills exist server-side — deep history is NOT queryable on HL, which is why
|
|
65
|
+
* the `trades` table must be WS-first. */
|
|
66
|
+
fetchMyTrades(symbol?: string, since?: number, limit?: number): Promise<unknown[] | null>;
|
|
67
|
+
/** Refresh the ADDRESS action budget (the starvation guard). Weight 20 — call
|
|
68
|
+
* every ~5 min, never per-heartbeat. */
|
|
69
|
+
refreshAddressBudget(): Promise<void>;
|
|
70
|
+
/** Raw `POST /info` — for the handful of reads CCXT doesn't expose
|
|
71
|
+
* (userRateLimit, userNonFundingLedgerUpdates, portfolio). Never used for
|
|
72
|
+
* signed actions. */
|
|
73
|
+
rawInfo(body: Record<string, unknown>): Promise<any>;
|
|
74
|
+
/** Submit one order. Market orders are IOC-limit emulated — `price` is
|
|
75
|
+
* MANDATORY (ccxt throws without it) and the caller must already have applied
|
|
76
|
+
* the slippage bound + HL rounding (hl-precision). */
|
|
77
|
+
submitOrder(req: HlOrderRequest): Promise<CcxtOrder | null>;
|
|
78
|
+
/** Submit N orders as ONE signed action (one nonce, one `/exchange` call).
|
|
79
|
+
* This is how a bracket pair (SL+TP) is placed: atomic-ish, and it costs 1 IP
|
|
80
|
+
* weight unit but N address actions. */
|
|
81
|
+
submitOrders(reqs: HlOrderRequest[]): Promise<CcxtOrder[] | null>;
|
|
82
|
+
cancelOrder(orderId: string, symbol: string): Promise<CcxtOrder | null>;
|
|
83
|
+
/** Cancel by cloid — the bracket path's cancel (we always know our own cloid,
|
|
84
|
+
* and it survives a restart because it is derived, not stored). */
|
|
85
|
+
cancelOrderByCloid(cloid: string, symbol: string): Promise<CcxtOrder | null>;
|
|
86
|
+
private buildParams;
|
|
87
|
+
get isMarketsLoaded(): boolean;
|
|
88
|
+
}
|