mirror of
https://github.com/himself65/finance-skills.git
synced 2026-09-14 14:40:40 +08:00
8072082fda
* feat: add hyperliquid-reader skill + opencli plugin Add a read-only Hyperliquid (app.hyperliquid.xyz) reader, mirroring the tradingview-reader pattern. Unlike TradingView's CDP attach, Hyperliquid exposes a fully public info API (POST https://api.hyperliquid.xyz/info), so this needs no API key, wallet, login, or desktop app. opencli plugin (opencli-plugins/hyperliquid/) — 12 read-only commands: - Market data: markets, spot-markets, mids, book, candles, funding-history, funding-compare (cross-venue HL/Binance/Bybit funding-arb screen). - Account by 0x address: account, positions, spot-balances, open-orders, fills. Skill (plugins/data-providers/skills/hyperliquid-reader/) — SKILL.md (5-step + error reference), README.md, references/commands.md. Registrations: root opencli-plugin.json, data-providers plugin.json (description + keywords), marketplace.json, root README table. Verification: 31 unit tests pass against captured live wire shapes; all 12 command data paths smoke-tested end-to-end against the live API. SKILL.md description is 1019 chars (< 1024 lint cap), no angle brackets. No trade execution: the plugin exposes no write/exchange endpoints. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * refactor: scope hyperliquid-reader to market data only Drop the account-by-address commands (account, positions, spot-balances, open-orders, fills) and their lib/account.js + lib/orders.js helpers and tests. Remove the now-unused normalizeAddress helper from lib/api.js. The reader is now market-data only: markets, spot-markets, mids, book, candles, funding-history, funding-compare (7 commands). Updated SKILL.md, both READMEs, references/commands.md, the plugin/marketplace manifests, and the root README table accordingly. 21 unit tests pass; all 7 market-data data paths re-verified live.
38 lines
1.5 KiB
JavaScript
38 lines
1.5 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { num, pctChange, fundingToApr, isoTime } from '../lib/api.js';
|
|
|
|
test('num — coerces numeric strings, else null', () => {
|
|
assert.equal(num('61791.0'), 61791);
|
|
assert.equal(num(42), 42);
|
|
assert.equal(num(0), 0);
|
|
assert.equal(num(null), null);
|
|
assert.equal(num(undefined), null);
|
|
assert.equal(num('not-a-number'), null);
|
|
});
|
|
|
|
test('pctChange — basic + guards', () => {
|
|
assert.equal(pctChange(110, 100), 10);
|
|
assert.equal(pctChange('61791.0', '61001.0').toFixed(4), '1.2951');
|
|
assert.equal(pctChange(100, 0), null);
|
|
assert.equal(pctChange(null, 100), null);
|
|
assert.equal(pctChange(100, null), null);
|
|
});
|
|
|
|
test('fundingToApr — hourly and multi-hour intervals', () => {
|
|
// 0.0000125 hourly → 0.0000125 * 24 * 365 * 100 = 10.95% APR
|
|
assert.equal(fundingToApr('0.0000125', 1).toFixed(4), '10.9500');
|
|
// Same rate over a 4h interval annualizes to a quarter of the hourly figure.
|
|
assert.equal(fundingToApr('0.0000125', 4).toFixed(5), '2.73750');
|
|
assert.equal(fundingToApr(null), null);
|
|
// Missing/zero interval defaults to hourly.
|
|
assert.equal(fundingToApr('0.0000125', 0).toFixed(4), '10.9500');
|
|
assert.equal(fundingToApr('0.0000125').toFixed(4), '10.9500');
|
|
});
|
|
|
|
test('isoTime — ms epoch → ISO, null-safe', () => {
|
|
assert.equal(isoTime(1780813166432), '2026-06-07T06:19:26.432Z');
|
|
assert.equal(isoTime(null), null);
|
|
assert.equal(isoTime('not-a-number'), null);
|
|
});
|