minara 0.3.0 → 0.4.0
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/README.md +25 -8
- package/dist/api/perps.d.ts +25 -1
- package/dist/api/perps.js +50 -0
- package/dist/commands/assets.js +56 -9
- package/dist/commands/balance.js +8 -3
- package/dist/commands/perps.js +1245 -203
- package/dist/types.d.ts +41 -0
- package/package.json +2 -1
- package/dist/api/copytrade.d.ts +0 -19
- package/dist/api/copytrade.js +0 -37
- package/dist/commands/copy-trade.d.ts +0 -2
- package/dist/commands/copy-trade.js +0 -170
package/README.md
CHANGED
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
- **AI Chat** — Crypto-native AI for on-chain analysis, market research, and DeFi due diligence. Interactive REPL & single-shot queries with `fast` / `quality` / `thinking` modes
|
|
22
22
|
- **Wallet & Balance** — Unified balance view, spot holdings with PnL, perps account overview, deposits, withdrawals, and credit card on-ramp via MoonPay
|
|
23
23
|
- **Chain-Abstracted Trading** — Cross-chain swaps with automatic chain detection, perpetual futures, and limit orders. Accepts `$TICKER`, token name, or contract address
|
|
24
|
-
- **
|
|
24
|
+
- **Multi-Wallet Perps** — Manage multiple sub-wallets per account: create, rename, sweep, transfer USDC between wallets. All trading commands support `--wallet` targeting
|
|
25
|
+
- **AI Autopilot & Analysis** — Multi-strategy AI trading per wallet with performance dashboard, strategy comparison table, and one-click config management. Plus on-demand long/short analysis with quick order
|
|
25
26
|
- **Market Discovery** — Trending tokens & stocks, Fear & Greed Index, on-chain metrics, and search
|
|
26
27
|
|
|
27
28
|
## Installation
|
|
@@ -135,28 +136,44 @@ minara swap --dry-run # Simulate without executing
|
|
|
135
136
|
| `minara perps deposit` | Deposit USDC to perps (or use `minara deposit perps`) |
|
|
136
137
|
| `minara perps withdraw` | Withdraw USDC from perps account |
|
|
137
138
|
| `minara perps fund-records` | View fund deposit/withdrawal records |
|
|
138
|
-
| `minara perps
|
|
139
|
+
| `minara perps wallets` | List all sub-wallets with balances and autopilot info |
|
|
140
|
+
| `minara perps create-wallet`| Create a new perps sub-wallet |
|
|
141
|
+
| `minara perps rename-wallet`| Rename a sub-wallet |
|
|
142
|
+
| `minara perps sweep` | Consolidate funds from sub-wallet to default |
|
|
143
|
+
| `minara perps transfer` | Transfer USDC between sub-wallets |
|
|
144
|
+
| `minara perps autopilot` | Manage AI autopilot strategies per wallet |
|
|
139
145
|
| `minara perps ask` | AI long/short analysis with quick order |
|
|
140
146
|
|
|
141
147
|
```bash
|
|
142
|
-
minara perps positions #
|
|
143
|
-
minara perps
|
|
148
|
+
minara perps positions # Positions per wallet with equity, margin, PnL
|
|
149
|
+
minara perps positions --wallet Bot-1 # Positions for a specific wallet only
|
|
150
|
+
minara perps order # Interactive: symbol → side → size → confirm
|
|
151
|
+
minara perps order --wallet Bot-1 # Place order on a specific wallet
|
|
144
152
|
minara perps close # Close a position: pick from list → market close
|
|
153
|
+
minara perps close --all # Close all positions at once
|
|
145
154
|
minara perps cancel # Cancel an order: pick from open orders list
|
|
146
155
|
minara perps leverage # Interactive: shows max leverage per asset
|
|
147
156
|
minara perps trades # Recent fills from Hyperliquid (default 7 days)
|
|
148
157
|
minara perps trades -d 30 # Last 30 days of trade history
|
|
149
158
|
minara perps deposit -a 100 # Deposit 100 USDC to perps
|
|
150
159
|
minara perps withdraw -a 50 # Withdraw 50 USDC from perps
|
|
151
|
-
minara perps
|
|
160
|
+
minara perps wallets # All wallets: equity, margin, PnL, strategies
|
|
161
|
+
minara perps create-wallet -n Bot-2 # Create a new sub-wallet
|
|
162
|
+
minara perps sweep # Move funds from a sub-wallet to default
|
|
163
|
+
minara perps transfer # Transfer USDC between any two wallets
|
|
164
|
+
minara perps autopilot # Strategy dashboard: enable/disable, config, perf
|
|
152
165
|
minara perps ask # AI analysis → optional quick order
|
|
153
166
|
```
|
|
154
167
|
|
|
168
|
+
> **Multi-wallet support:** All trading commands (`order`, `deposit`, `withdraw`, `close`, `cancel`, `leverage`, `trades`, `fund-records`, `ask`) accept `--wallet <name>` to target a specific sub-wallet. If omitted, you'll be prompted to pick one interactively.
|
|
169
|
+
>
|
|
170
|
+
> **Autopilot dashboard:** Each wallet can have multiple AI strategies. The dashboard shows strategy name, status, config, and a performance comparison table across all available strategies with the active one highlighted.
|
|
171
|
+
>
|
|
155
172
|
> **Close position:** Select an open position from the list, and it will be closed at market price with a reduce-only order in the opposite direction — no manual price or size entry needed.
|
|
156
173
|
>
|
|
157
174
|
> **Cancel order:** Open orders are fetched from Hyperliquid and shown as a selectable list with coin, side, size, and price — no need to look up order IDs.
|
|
158
175
|
>
|
|
159
|
-
> **Autopilot:** When autopilot is ON, manual order placement
|
|
176
|
+
> **Autopilot:** When autopilot is ON for a wallet, manual order placement on that wallet is blocked to prevent conflicts with AI-managed trades. Turn off autopilot first via `minara perps autopilot`.
|
|
160
177
|
>
|
|
161
178
|
> **Ask AI → Quick Order:** After the AI analysis, you can instantly place a market order based on the recommended direction, entry price, and position size — no need to re-enter parameters.
|
|
162
179
|
|
|
@@ -340,12 +357,12 @@ minara --help
|
|
|
340
357
|
|
|
341
358
|
## Testing
|
|
342
359
|
|
|
343
|
-
Test suite built with [Vitest](https://vitest.dev/) —
|
|
360
|
+
Test suite built with [Vitest](https://vitest.dev/) — 251 tests covering unit, API, command integration, and formatter layers.
|
|
344
361
|
|
|
345
362
|
```bash
|
|
346
363
|
npm test # Run all tests
|
|
347
364
|
npm run test:watch # Watch mode
|
|
348
|
-
npm run test:coverage # With coverage report
|
|
365
|
+
npm run test:coverage # With v8 coverage report
|
|
349
366
|
```
|
|
350
367
|
|
|
351
368
|
## Security
|
package/dist/api/perps.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PerpsDepositDto, PerpsWithdrawDto, PerpsPlaceOrdersDto, PerpsCancelOrdersDto, UpdateLeverageDto, PerpsPosition, TokenPrice, TransactionResult } from '../types.js';
|
|
1
|
+
import type { PerpsDepositDto, PerpsWithdrawDto, PerpsPlaceOrdersDto, PerpsCancelOrdersDto, UpdateLeverageDto, PerpsPosition, TokenPrice, TransactionResult, PerpSubAccount, CreatePerpSubAccountDto, RenamePerpSubAccountDto, TransferFundsDto, SweepFundsDto } from '../types.js';
|
|
2
2
|
/** Deposit USDC to perps (min 5 USDC) */
|
|
3
3
|
export declare function deposit(token: string, dto: PerpsDepositDto): Promise<import("../types.js").ApiResponse<TransactionResult>>;
|
|
4
4
|
/** Withdraw USDC from perps */
|
|
@@ -33,6 +33,7 @@ export declare function createStrategy(token: string, dto: {
|
|
|
33
33
|
symbols: string[];
|
|
34
34
|
strategyConfig?: Record<string, unknown>;
|
|
35
35
|
language?: string;
|
|
36
|
+
subAccountId?: string;
|
|
36
37
|
}): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
37
38
|
export declare function enableStrategy(token: string, strategyId: string): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
38
39
|
export declare function disableStrategy(token: string, strategyId: string): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
@@ -43,6 +44,29 @@ export declare function updateStrategy(token: string, dto: {
|
|
|
43
44
|
language?: string;
|
|
44
45
|
}): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
45
46
|
export declare function getPerformanceMetrics(token: string): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
47
|
+
export declare function getMinEquityValue(token: string): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
48
|
+
export declare function setMinEquityValue(token: string, dto: Record<string, unknown>): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
49
|
+
export declare function getRecords(token: string, page: number, limit: number): Promise<import("../types.js").ApiResponse<Record<string, unknown>[]>>;
|
|
50
|
+
/** List all perp sub-accounts */
|
|
51
|
+
export declare function listSubAccounts(token: string): Promise<import("../types.js").ApiResponse<PerpSubAccount[]>>;
|
|
52
|
+
/** Create a new perp sub-account */
|
|
53
|
+
export declare function createSubAccount(token: string, dto: CreatePerpSubAccountDto): Promise<import("../types.js").ApiResponse<PerpSubAccount>>;
|
|
54
|
+
/** Rename a perp sub-account */
|
|
55
|
+
export declare function renameSubAccount(token: string, dto: RenamePerpSubAccountDto): Promise<import("../types.js").ApiResponse<void>>;
|
|
56
|
+
/** Get summary for a specific sub-account */
|
|
57
|
+
export declare function getSubAccountSummary(token: string, subAccountId: string): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
58
|
+
/** Get aggregated PnL across all sub-accounts */
|
|
59
|
+
export declare function getAggregatedSummary(token: string): Promise<import("../types.js").ApiResponse<Record<string, unknown>>>;
|
|
60
|
+
/** Get autopilot records for a specific sub-account */
|
|
61
|
+
export declare function getSubAccountRecords(token: string, subAccountId: string, page: number, limit: number): Promise<import("../types.js").ApiResponse<Record<string, unknown>[]>>;
|
|
62
|
+
/** Get fills for a specific sub-account */
|
|
63
|
+
export declare function getSubAccountFills(token: string, subAccountId: string, startTime: number): Promise<import("../types.js").ApiResponse<Record<string, unknown>[]>>;
|
|
64
|
+
/** Get open orders for a specific sub-account */
|
|
65
|
+
export declare function getSubAccountOpenOrders(token: string, subAccountId: string): Promise<import("../types.js").ApiResponse<Record<string, unknown>[]>>;
|
|
66
|
+
/** Transfer USDC between sub-accounts (internal, no gas) */
|
|
67
|
+
export declare function transferFunds(token: string, dto: TransferFundsDto): Promise<import("../types.js").ApiResponse<TransactionResult>>;
|
|
68
|
+
/** Sweep all funds from a sub-account back to the default account */
|
|
69
|
+
export declare function sweepFunds(token: string, dto: SweepFundsDto): Promise<import("../types.js").ApiResponse<TransactionResult>>;
|
|
46
70
|
export declare function priceAnalysis(token: string, dto: {
|
|
47
71
|
symbol: string;
|
|
48
72
|
startTime?: number;
|
package/dist/api/perps.js
CHANGED
|
@@ -77,6 +77,56 @@ export function updateStrategy(token, dto) {
|
|
|
77
77
|
export function getPerformanceMetrics(token) {
|
|
78
78
|
return get('/v1/fully-managed/performance/metrics/v2', { token });
|
|
79
79
|
}
|
|
80
|
+
export function getMinEquityValue(token) {
|
|
81
|
+
return get('/v1/fully-managed/get-min-equity-value', { token });
|
|
82
|
+
}
|
|
83
|
+
export function setMinEquityValue(token, dto) {
|
|
84
|
+
return post('/v1/fully-managed/set-min-equity-value', { token, body: dto });
|
|
85
|
+
}
|
|
86
|
+
export function getRecords(token, page, limit) {
|
|
87
|
+
return get('/v1/fully-managed/records', { token, query: { page, limit } });
|
|
88
|
+
}
|
|
89
|
+
// ── Perp Wallets (multi sub-account) ──────────────────────────────────────
|
|
90
|
+
/** List all perp sub-accounts */
|
|
91
|
+
export function listSubAccounts(token) {
|
|
92
|
+
return get('/v1/perp-wallets', { token });
|
|
93
|
+
}
|
|
94
|
+
/** Create a new perp sub-account */
|
|
95
|
+
export function createSubAccount(token, dto) {
|
|
96
|
+
return post('/v1/perp-wallets', { token, body: dto });
|
|
97
|
+
}
|
|
98
|
+
/** Rename a perp sub-account */
|
|
99
|
+
export function renameSubAccount(token, dto) {
|
|
100
|
+
return post('/v1/perp-wallets/rename', { token, body: dto });
|
|
101
|
+
}
|
|
102
|
+
/** Get summary for a specific sub-account */
|
|
103
|
+
export function getSubAccountSummary(token, subAccountId) {
|
|
104
|
+
return get('/v1/perp-wallets/summary', { token, query: { subAccountId } });
|
|
105
|
+
}
|
|
106
|
+
/** Get aggregated PnL across all sub-accounts */
|
|
107
|
+
export function getAggregatedSummary(token) {
|
|
108
|
+
return get('/v1/perp-wallets/aggregated-summary', { token });
|
|
109
|
+
}
|
|
110
|
+
/** Get autopilot records for a specific sub-account */
|
|
111
|
+
export function getSubAccountRecords(token, subAccountId, page, limit) {
|
|
112
|
+
return get('/v1/perp-wallets/records', { token, query: { subAccountId, page, limit } });
|
|
113
|
+
}
|
|
114
|
+
/** Get fills for a specific sub-account */
|
|
115
|
+
export function getSubAccountFills(token, subAccountId, startTime) {
|
|
116
|
+
return get('/v1/perp-wallets/fills', { token, query: { subAccountId, startTime } });
|
|
117
|
+
}
|
|
118
|
+
/** Get open orders for a specific sub-account */
|
|
119
|
+
export function getSubAccountOpenOrders(token, subAccountId) {
|
|
120
|
+
return get('/v1/perp-wallets/open-orders', { token, query: { subAccountId } });
|
|
121
|
+
}
|
|
122
|
+
/** Transfer USDC between sub-accounts (internal, no gas) */
|
|
123
|
+
export function transferFunds(token, dto) {
|
|
124
|
+
return post('/v1/perp-wallets/transfer', { token, body: dto });
|
|
125
|
+
}
|
|
126
|
+
/** Sweep all funds from a sub-account back to the default account */
|
|
127
|
+
export function sweepFunds(token, dto) {
|
|
128
|
+
return post('/v1/perp-wallets/sweep', { token, body: dto });
|
|
129
|
+
}
|
|
80
130
|
// ── Price Analysis (Ask Long/Short) ──────────────────────────────────────
|
|
81
131
|
export function priceAnalysis(token, dto) {
|
|
82
132
|
return post('/tokens/price-analysis', { token, body: dto });
|
package/dist/commands/assets.js
CHANGED
|
@@ -79,9 +79,63 @@ const perpsCmd = new Command('perps')
|
|
|
79
79
|
await showPerpsAssets(creds.accessToken);
|
|
80
80
|
}));
|
|
81
81
|
async function showPerpsAssets(token) {
|
|
82
|
-
const spin = spinner('Fetching perps
|
|
83
|
-
const
|
|
82
|
+
const spin = spinner('Fetching perps wallets…');
|
|
83
|
+
const walletsRes = await perpsApi.listSubAccounts(token);
|
|
84
84
|
spin.stop();
|
|
85
|
+
let wallets = [];
|
|
86
|
+
if (walletsRes.success && walletsRes.data) {
|
|
87
|
+
const raw = walletsRes.data;
|
|
88
|
+
if (Array.isArray(raw))
|
|
89
|
+
wallets = raw;
|
|
90
|
+
else if (raw && typeof raw === 'object') {
|
|
91
|
+
const inner = raw.data
|
|
92
|
+
?? raw.subAccounts
|
|
93
|
+
?? raw.wallets;
|
|
94
|
+
if (Array.isArray(inner))
|
|
95
|
+
wallets = inner;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const fmt = (n) => `$${n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
99
|
+
const pnlFmt = (n) => {
|
|
100
|
+
const color = n >= 0 ? chalk.green : chalk.red;
|
|
101
|
+
return color(`${n >= 0 ? '+' : ''}${fmt(n)}`);
|
|
102
|
+
};
|
|
103
|
+
if (wallets.length > 0) {
|
|
104
|
+
console.log('');
|
|
105
|
+
console.log(chalk.bold(`Perps Wallets (${wallets.length}):`));
|
|
106
|
+
for (const w of wallets) {
|
|
107
|
+
const name = String(w.name ?? 'Unnamed');
|
|
108
|
+
const def = w.isDefault ? chalk.cyan(' (default)') : '';
|
|
109
|
+
console.log('');
|
|
110
|
+
console.log(chalk.bold(` ${name}${def}:`));
|
|
111
|
+
console.log(` Equity : ${fmt(Number(w.equityValue ?? 0))}`);
|
|
112
|
+
console.log(` Available : ${fmt(Number(w.dispatchableValue ?? 0))}`);
|
|
113
|
+
console.log(` Margin Used : ${fmt(Number(w.totalMarginUsed ?? 0))}`);
|
|
114
|
+
console.log(` Unrealized PnL: ${pnlFmt(Number(w.totalUnrealizedPnl ?? 0))}`);
|
|
115
|
+
const positions = Array.isArray(w.positions) ? w.positions : [];
|
|
116
|
+
if (positions.length > 0) {
|
|
117
|
+
printTable(positions, POSITION_COLUMNS);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.log(chalk.dim(' No open positions.'));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Aggregated summary
|
|
124
|
+
const aggRes = await perpsApi.getAggregatedSummary(token);
|
|
125
|
+
if (aggRes.success && aggRes.data) {
|
|
126
|
+
const d = aggRes.data;
|
|
127
|
+
console.log('');
|
|
128
|
+
console.log(chalk.bold(' Aggregated:'));
|
|
129
|
+
console.log(` Total Equity : ${fmt(Number(d.totalEquity ?? d.equityValue ?? 0))}`);
|
|
130
|
+
console.log(` Total Unrl. PnL : ${pnlFmt(Number(d.totalUnrealizedPnl ?? 0))}`);
|
|
131
|
+
}
|
|
132
|
+
console.log('');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// Fallback to legacy single-account API
|
|
136
|
+
const legacySpin = spinner('Fetching perps account…');
|
|
137
|
+
const res = await perpsApi.getAccountSummary(token);
|
|
138
|
+
legacySpin.stop();
|
|
85
139
|
if (!res.success || !res.data) {
|
|
86
140
|
console.log(chalk.dim(' Could not fetch perps account.'));
|
|
87
141
|
if (res.error?.message)
|
|
@@ -89,12 +143,6 @@ async function showPerpsAssets(token) {
|
|
|
89
143
|
return;
|
|
90
144
|
}
|
|
91
145
|
const d = res.data;
|
|
92
|
-
const fmt = (n) => `$${n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
93
|
-
const pnlFmt = (n) => {
|
|
94
|
-
const color = n >= 0 ? chalk.green : chalk.red;
|
|
95
|
-
return color(`${n >= 0 ? '+' : ''}${fmt(n)}`);
|
|
96
|
-
};
|
|
97
|
-
// ── Account overview ───────────────────────────────────────────────
|
|
98
146
|
console.log('');
|
|
99
147
|
console.log(chalk.bold('Perps Account:'));
|
|
100
148
|
console.log(` Equity : ${fmt(Number(d.equityValue ?? 0))}`);
|
|
@@ -102,7 +150,6 @@ async function showPerpsAssets(token) {
|
|
|
102
150
|
console.log(` Margin Used : ${fmt(Number(d.totalMarginUsed ?? 0))}`);
|
|
103
151
|
console.log(` Unrealized PnL: ${pnlFmt(Number(d.totalUnrealizedPnl ?? 0))}`);
|
|
104
152
|
console.log(` Withdrawable : ${fmt(Number(d.withdrawableValue ?? 0))}`);
|
|
105
|
-
// ── Positions ───────────────────────────────────────────────────────
|
|
106
153
|
const positions = Array.isArray(d.positions) ? d.positions : [];
|
|
107
154
|
console.log('');
|
|
108
155
|
console.log(chalk.bold(`Open Positions (${positions.length}):`));
|
package/dist/commands/balance.js
CHANGED
|
@@ -10,8 +10,9 @@ export const balanceCommand = new Command('balance')
|
|
|
10
10
|
.action(wrapAction(async () => {
|
|
11
11
|
const creds = requireAuth();
|
|
12
12
|
const spin = spinner('Fetching balances…');
|
|
13
|
-
const [spotRes,
|
|
13
|
+
const [spotRes, perpsAggRes, perpsLegacyRes] = await Promise.all([
|
|
14
14
|
get('/users/pnls/all', { token: creds.accessToken }),
|
|
15
|
+
perpsApi.getAggregatedSummary(creds.accessToken),
|
|
15
16
|
perpsApi.getAccountSummary(creds.accessToken),
|
|
16
17
|
]);
|
|
17
18
|
spin.stop();
|
|
@@ -28,8 +29,12 @@ export const balanceCommand = new Command('balance')
|
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
let perpsAvailable = 0;
|
|
31
|
-
if (
|
|
32
|
-
const d =
|
|
32
|
+
if (perpsAggRes.success && perpsAggRes.data) {
|
|
33
|
+
const d = perpsAggRes.data;
|
|
34
|
+
perpsAvailable = Number(d.totalDispatchable ?? d.dispatchableValue ?? d.totalEquity ?? 0);
|
|
35
|
+
}
|
|
36
|
+
else if (perpsLegacyRes.success && perpsLegacyRes.data) {
|
|
37
|
+
const d = perpsLegacyRes.data;
|
|
33
38
|
perpsAvailable = Number(d.dispatchableValue ?? 0);
|
|
34
39
|
}
|
|
35
40
|
const total = spotStable + perpsAvailable;
|