@alphafox/cli 0.3.6 → 0.3.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/dist/catalog/omit.d.ts +3 -1
- package/dist/catalog/omit.js +9 -2
- package/dist/commands/run.js +1 -1
- package/dist/resolve-symbols/catalog.d.ts +6 -0
- package/dist/resolve-symbols/catalog.js +43 -0
- package/dist/resolve-symbols/exchanges.js +7 -4
- package/dist/resolve-symbols/match.d.ts +4 -3
- package/dist/resolve-symbols/match.js +50 -48
- package/dist/resolve-symbols/parse-args.d.ts +1 -0
- package/dist/resolve-symbols/parse-args.js +20 -3
- package/dist/resolve-symbols/run-command.js +19 -6
- package/dist/resolve-symbols/types.d.ts +14 -0
- package/dist/skills-manifest.json +41 -41
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/account/SKILL.md +1 -1
- package/skills/admin/SKILL.md +1 -1
- package/skills/alphafox/SKILL.md +11 -9
- package/skills/alphafox-shared/SKILL.md +3 -3
- package/skills/auth/SKILL.md +1 -1
- package/skills/engine-backtest/SKILL.md +5 -5
- package/skills/exchange/SKILL.md +1 -1
- package/skills/market/SKILL.md +32 -12
- package/skills/notification/SKILL.md +1 -1
- package/skills/strategy/SKILL.md +17 -15
- package/skills/trading/SKILL.md +37 -7
package/dist/catalog/omit.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Not a CLI surface:
|
|
3
|
+
* - Web `/api/v1/backtests` jobs (`backtests` / `backtests.*`)
|
|
4
|
+
* - Chat product (`chats` / `chats.*`, `chat_summaries` / `chat_summaries.*`)
|
|
3
5
|
* Local Engine WASM (`engine-backtest run`) and `engine_backtest.*` stay.
|
|
4
6
|
* Match `backtests` / `backtests.*` only — never `engine_backtest.*`.
|
|
5
7
|
*/
|
package/dist/catalog/omit.js
CHANGED
|
@@ -2,10 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isOmittedCatalogOperation = isOmittedCatalogOperation;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Not a CLI surface:
|
|
6
|
+
* - Web `/api/v1/backtests` jobs (`backtests` / `backtests.*`)
|
|
7
|
+
* - Chat product (`chats` / `chats.*`, `chat_summaries` / `chat_summaries.*`)
|
|
6
8
|
* Local Engine WASM (`engine-backtest run`) and `engine_backtest.*` stay.
|
|
7
9
|
* Match `backtests` / `backtests.*` only — never `engine_backtest.*`.
|
|
8
10
|
*/
|
|
9
11
|
function isOmittedCatalogOperation(operationId) {
|
|
10
|
-
return operationId === "backtests" ||
|
|
12
|
+
return (operationId === "backtests" ||
|
|
13
|
+
operationId.startsWith("backtests.") ||
|
|
14
|
+
operationId === "chats" ||
|
|
15
|
+
operationId.startsWith("chats.") ||
|
|
16
|
+
operationId === "chat_summaries" ||
|
|
17
|
+
operationId.startsWith("chat_summaries."));
|
|
11
18
|
}
|
package/dist/commands/run.js
CHANGED
|
@@ -101,7 +101,7 @@ async function runCli(argv, env = process.env) {
|
|
|
101
101
|
"alphafox api METHOD PATH [--body JSON|--config @file]",
|
|
102
102
|
"alphafox engine-backtest run --experiment <uuid> --definition <id> --config @file --exchange <id> --range FROM..TO --initial-equity N",
|
|
103
103
|
"alphafox engine-backtest sweep --experiment <uuid> --definition <id> --config @file --axes @file --exchange <id> --range FROM..TO --initial-equity N --no-persist",
|
|
104
|
-
"alphafox resolve-symbols <query...> [--exchange binance]",
|
|
104
|
+
"alphafox resolve-symbols <query...> [--exchange binance] [--asset-class equity_perp]",
|
|
105
105
|
"alphafox <domain> <resource> <action> [flags]",
|
|
106
106
|
],
|
|
107
107
|
}, { format: flags.format, jq: flags.jq });
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import type { SymbolMetadata } from "./types";
|
|
1
2
|
export declare const MARKET_SYMBOLS_PATH = "/api/v1/market/symbols";
|
|
2
3
|
export declare function marketSymbolsPath(exchangeId: string): string;
|
|
4
|
+
export interface MarketCatalogPayload {
|
|
5
|
+
readonly symbols: string[];
|
|
6
|
+
readonly symbolMetadata: Readonly<Record<string, SymbolMetadata>>;
|
|
7
|
+
}
|
|
3
8
|
export declare function extractCatalogSymbols(json: unknown): string[];
|
|
9
|
+
export declare function extractMarketCatalog(json: unknown): MarketCatalogPayload;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MARKET_SYMBOLS_PATH = void 0;
|
|
4
4
|
exports.marketSymbolsPath = marketSymbolsPath;
|
|
5
5
|
exports.extractCatalogSymbols = extractCatalogSymbols;
|
|
6
|
+
exports.extractMarketCatalog = extractMarketCatalog;
|
|
6
7
|
const errors_1 = require("./errors");
|
|
7
8
|
exports.MARKET_SYMBOLS_PATH = "/api/v1/market/symbols";
|
|
8
9
|
function marketSymbolsPath(exchangeId) {
|
|
@@ -10,6 +11,9 @@ function marketSymbolsPath(exchangeId) {
|
|
|
10
11
|
return `${exports.MARKET_SYMBOLS_PATH}?${query}`;
|
|
11
12
|
}
|
|
12
13
|
function extractCatalogSymbols(json) {
|
|
14
|
+
return extractMarketCatalog(json).symbols;
|
|
15
|
+
}
|
|
16
|
+
function extractMarketCatalog(json) {
|
|
13
17
|
const root = asRecord(json);
|
|
14
18
|
const payload = asRecord(root?.data) ?? root;
|
|
15
19
|
const symbols = payload?.symbols;
|
|
@@ -40,8 +44,47 @@ function extractCatalogSymbols(json) {
|
|
|
40
44
|
details: json,
|
|
41
45
|
});
|
|
42
46
|
}
|
|
47
|
+
return {
|
|
48
|
+
symbols: out,
|
|
49
|
+
symbolMetadata: extractSymbolMetadata(payload?.symbolMetadata),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function extractSymbolMetadata(value) {
|
|
53
|
+
const rec = asRecord(value);
|
|
54
|
+
if (!rec)
|
|
55
|
+
return {};
|
|
56
|
+
const out = {};
|
|
57
|
+
for (const [rawKey, rawMeta] of Object.entries(rec)) {
|
|
58
|
+
const key = rawKey.trim();
|
|
59
|
+
const meta = parseSymbolMetadata(rawMeta);
|
|
60
|
+
if (!key || !meta)
|
|
61
|
+
continue;
|
|
62
|
+
out[key] = meta;
|
|
63
|
+
}
|
|
43
64
|
return out;
|
|
44
65
|
}
|
|
66
|
+
function parseSymbolMetadata(value) {
|
|
67
|
+
const rec = asRecord(value);
|
|
68
|
+
if (!rec)
|
|
69
|
+
return undefined;
|
|
70
|
+
const meta = {};
|
|
71
|
+
if (typeof rec.isTradFiRwa === "boolean") {
|
|
72
|
+
meta.isTradFiRwa = rec.isTradFiRwa;
|
|
73
|
+
}
|
|
74
|
+
if (typeof rec.assetClass === "string" && rec.assetClass.trim()) {
|
|
75
|
+
meta.assetClass = rec.assetClass.trim();
|
|
76
|
+
}
|
|
77
|
+
if (isFiniteNumber(rec.minAmount))
|
|
78
|
+
meta.minAmount = rec.minAmount;
|
|
79
|
+
if (isFiniteNumber(rec.minCost))
|
|
80
|
+
meta.minCost = rec.minCost;
|
|
81
|
+
if (isFiniteNumber(rec.contractSize))
|
|
82
|
+
meta.contractSize = rec.contractSize;
|
|
83
|
+
return Object.keys(meta).length > 0 ? meta : undefined;
|
|
84
|
+
}
|
|
85
|
+
function isFiniteNumber(value) {
|
|
86
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
87
|
+
}
|
|
45
88
|
function asRecord(value) {
|
|
46
89
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
47
90
|
return undefined;
|
|
@@ -42,12 +42,15 @@ for (const exchange of exports.RESOLVE_SYMBOLS_EXCHANGES) {
|
|
|
42
42
|
EXCHANGE_BY_ALIAS.set(alias.toLowerCase(), exchange);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
+
const PASSTHROUGH_EXCHANGE_ID = /^[a-z][a-z0-9_]{1,63}$/;
|
|
45
46
|
function resolveSymbolsExchangeId(raw) {
|
|
46
47
|
const key = raw.trim().toLowerCase();
|
|
47
48
|
const exchange = EXCHANGE_BY_ALIAS.get(key);
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
if (exchange)
|
|
50
|
+
return exchange;
|
|
51
|
+
if (PASSTHROUGH_EXCHANGE_ID.test(key)) {
|
|
52
|
+
return { id: key, label: raw.trim(), aliases: [key] };
|
|
51
53
|
}
|
|
52
|
-
|
|
54
|
+
const allowed = exports.RESOLVE_SYMBOLS_EXCHANGES.map((item) => item.aliases[0]).join("|");
|
|
55
|
+
throw new Error(`--exchange must be ${allowed} or a market.symbols.list catalog id (got ${raw.trim() || "<empty>"})`);
|
|
53
56
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { CatalogSymbol, ResolveSymbolsQueryResult } from "./types";
|
|
1
|
+
import type { CatalogSymbol, ResolveAssetClassFilter, ResolveSymbolsQueryResult, SymbolMetadata } from "./types";
|
|
2
2
|
export declare function normalizeSymbolSearchKey(value: string): string;
|
|
3
3
|
export declare function parseCatalogSymbol(symbol: string): CatalogSymbol | null;
|
|
4
|
-
export declare function indexCatalogSymbols(symbols: readonly string[]): readonly CatalogSymbol[];
|
|
5
|
-
export declare function
|
|
4
|
+
export declare function indexCatalogSymbols(symbols: readonly string[], metadata?: Readonly<Record<string, SymbolMetadata>>): readonly CatalogSymbol[];
|
|
5
|
+
export declare function catalogMatchesAssetClass(item: CatalogSymbol, assetClass: ResolveAssetClassFilter): boolean;
|
|
6
|
+
export declare function resolveQueryAgainstCatalog(query: string, catalog: readonly CatalogSymbol[], limit?: number, assetClass?: ResolveAssetClassFilter): ResolveSymbolsQueryResult;
|
|
6
7
|
export declare function levenshtein(left: string, right: string): number;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.normalizeSymbolSearchKey = normalizeSymbolSearchKey;
|
|
4
4
|
exports.parseCatalogSymbol = parseCatalogSymbol;
|
|
5
5
|
exports.indexCatalogSymbols = indexCatalogSymbols;
|
|
6
|
+
exports.catalogMatchesAssetClass = catalogMatchesAssetClass;
|
|
6
7
|
exports.resolveQueryAgainstCatalog = resolveQueryAgainstCatalog;
|
|
7
8
|
exports.levenshtein = levenshtein;
|
|
8
9
|
const LINEAR_PERP_PATTERN = /^([\p{L}\p{N}]+(?:-[\p{L}\p{N}]+)*)\/(USDT|USDC|USD):\2$/u;
|
|
@@ -69,7 +70,7 @@ function parseCatalogSymbol(symbol) {
|
|
|
69
70
|
compactKey: normalizeSymbolSearchKey(upper),
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
|
-
function indexCatalogSymbols(symbols) {
|
|
73
|
+
function indexCatalogSymbols(symbols, metadata = {}) {
|
|
73
74
|
const seen = new Set();
|
|
74
75
|
const indexed = [];
|
|
75
76
|
for (const raw of symbols) {
|
|
@@ -79,64 +80,59 @@ function indexCatalogSymbols(symbols) {
|
|
|
79
80
|
if (seen.has(parsed.symbol))
|
|
80
81
|
continue;
|
|
81
82
|
seen.add(parsed.symbol);
|
|
82
|
-
indexed.push(
|
|
83
|
+
indexed.push({
|
|
84
|
+
...parsed,
|
|
85
|
+
metadata: metadata[raw] ?? metadata[parsed.symbol],
|
|
86
|
+
});
|
|
83
87
|
}
|
|
84
88
|
return indexed;
|
|
85
89
|
}
|
|
86
|
-
function
|
|
90
|
+
function catalogMatchesAssetClass(item, assetClass) {
|
|
91
|
+
if (assetClass === "all")
|
|
92
|
+
return true;
|
|
93
|
+
const cls = item.metadata?.assetClass;
|
|
94
|
+
const tradfi = item.metadata?.isTradFiRwa === true;
|
|
95
|
+
if (assetClass === "equity_perp")
|
|
96
|
+
return cls === "equity_perp";
|
|
97
|
+
if (assetClass === "rwa_perp")
|
|
98
|
+
return cls === "rwa_perp";
|
|
99
|
+
return !tradfi && cls !== "equity_perp" && cls !== "rwa_perp";
|
|
100
|
+
}
|
|
101
|
+
function resolveQueryAgainstCatalog(query, catalog, limit = 8, assetClass = "all") {
|
|
87
102
|
const trimmed = query.trim();
|
|
88
|
-
const
|
|
103
|
+
const scoped = catalog.filter((item) => catalogMatchesAssetClass(item, assetClass));
|
|
104
|
+
const matches = rankMatches(trimmed, scoped);
|
|
89
105
|
const exact = matches.filter((item) => EXACT_REASONS.has(item.reason));
|
|
90
106
|
const close = matches.filter((item) => !EXACT_REASONS.has(item.reason));
|
|
91
107
|
const capped = (items) => items.slice(0, Math.max(1, limit));
|
|
92
108
|
if (exact.length === 1) {
|
|
93
|
-
return
|
|
94
|
-
query: trimmed,
|
|
95
|
-
status: "exact",
|
|
96
|
-
resolved: exact[0].symbol,
|
|
97
|
-
needsConfirmation: false,
|
|
98
|
-
matches: exact,
|
|
99
|
-
matchCount: exact.length,
|
|
100
|
-
};
|
|
109
|
+
return result("exact", exact[0].symbol, false, exact, exact.length);
|
|
101
110
|
}
|
|
102
111
|
if (exact.length > 1) {
|
|
103
|
-
return
|
|
104
|
-
query: trimmed,
|
|
105
|
-
status: "ambiguous",
|
|
106
|
-
resolved: null,
|
|
107
|
-
needsConfirmation: true,
|
|
108
|
-
matches: capped(exact),
|
|
109
|
-
matchCount: exact.length,
|
|
110
|
-
};
|
|
112
|
+
return result("ambiguous", null, true, capped(exact), exact.length);
|
|
111
113
|
}
|
|
112
114
|
if (close.length === 1) {
|
|
113
|
-
return
|
|
114
|
-
query: trimmed,
|
|
115
|
-
status: "close",
|
|
116
|
-
resolved: close[0].symbol,
|
|
117
|
-
needsConfirmation: true,
|
|
118
|
-
matches: close,
|
|
119
|
-
matchCount: 1,
|
|
120
|
-
};
|
|
115
|
+
return result("close", close[0].symbol, true, close, 1);
|
|
121
116
|
}
|
|
122
117
|
if (close.length > 1) {
|
|
118
|
+
return result("ambiguous", null, true, capped(close), close.length);
|
|
119
|
+
}
|
|
120
|
+
return result("none", null, false, [], 0);
|
|
121
|
+
function result(status, resolved, needsConfirmation, matches, matchCount) {
|
|
122
|
+
const chosen = resolved
|
|
123
|
+
? matches.find((item) => item.symbol === resolved)
|
|
124
|
+
: undefined;
|
|
123
125
|
return {
|
|
124
126
|
query: trimmed,
|
|
125
|
-
status
|
|
126
|
-
resolved
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
status,
|
|
128
|
+
resolved,
|
|
129
|
+
assetClass: chosen?.assetClass ?? null,
|
|
130
|
+
isTradFiRwa: chosen?.isTradFiRwa ?? false,
|
|
131
|
+
needsConfirmation,
|
|
132
|
+
matches,
|
|
133
|
+
matchCount,
|
|
130
134
|
};
|
|
131
135
|
}
|
|
132
|
-
return {
|
|
133
|
-
query: trimmed,
|
|
134
|
-
status: "none",
|
|
135
|
-
resolved: null,
|
|
136
|
-
needsConfirmation: false,
|
|
137
|
-
matches: [],
|
|
138
|
-
matchCount: 0,
|
|
139
|
-
};
|
|
140
136
|
}
|
|
141
137
|
function rankMatches(query, catalog) {
|
|
142
138
|
const canonicalQuery = query.trim().toUpperCase();
|
|
@@ -161,21 +157,21 @@ function rankMatches(query, catalog) {
|
|
|
161
157
|
}
|
|
162
158
|
function rankCatalogSymbol(item, canonicalQuery, queryKey, queryBaseKey) {
|
|
163
159
|
if (item.symbol === canonicalQuery) {
|
|
164
|
-
return match(item
|
|
160
|
+
return match(item, "exact_canonical", 100);
|
|
165
161
|
}
|
|
166
162
|
if (item.pair === canonicalQuery) {
|
|
167
|
-
return match(item
|
|
163
|
+
return match(item, "exact_pair", 96);
|
|
168
164
|
}
|
|
169
165
|
if (item.compactKey === queryKey || item.searchKey === queryKey) {
|
|
170
|
-
return match(item
|
|
166
|
+
return match(item, "exact_compact", 98);
|
|
171
167
|
}
|
|
172
168
|
if (item.baseKey === queryKey || item.baseKey === queryBaseKey) {
|
|
173
|
-
return match(item
|
|
169
|
+
return match(item, "exact_base", 95);
|
|
174
170
|
}
|
|
175
171
|
let best = null;
|
|
176
172
|
const consider = (reason, score) => {
|
|
177
173
|
if (!best || score > best.score) {
|
|
178
|
-
best = match(item
|
|
174
|
+
best = match(item, reason, score);
|
|
179
175
|
}
|
|
180
176
|
};
|
|
181
177
|
if (queryBaseKey.length >= 2 && item.baseKey.startsWith(queryBaseKey)) {
|
|
@@ -219,8 +215,14 @@ function isCloseDistance(left, right, distance) {
|
|
|
219
215
|
return distance === 1;
|
|
220
216
|
return distance <= 2;
|
|
221
217
|
}
|
|
222
|
-
function match(
|
|
223
|
-
return {
|
|
218
|
+
function match(item, reason, score) {
|
|
219
|
+
return {
|
|
220
|
+
symbol: item.symbol,
|
|
221
|
+
reason,
|
|
222
|
+
score,
|
|
223
|
+
assetClass: item.metadata?.assetClass ?? null,
|
|
224
|
+
isTradFiRwa: item.metadata?.isTradFiRwa === true,
|
|
225
|
+
};
|
|
224
226
|
}
|
|
225
227
|
function clampScore(score) {
|
|
226
228
|
return Math.max(1, Math.min(94, score));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ResolveSymbolsRunArgs } from "./types";
|
|
2
2
|
export declare const RESOLVE_SYMBOLS_DEFAULT_LIMIT = 8;
|
|
3
3
|
export declare const RESOLVE_SYMBOLS_MAX_LIMIT = 25;
|
|
4
|
+
export declare const RESOLVE_SYMBOLS_ASSET_CLASSES: readonly ["all", "equity_perp", "rwa_perp", "crypto"];
|
|
4
5
|
export declare const RESOLVE_SYMBOLS_USAGE: string[];
|
|
5
6
|
export declare function parseResolveSymbolsArgs(args: readonly string[]): ResolveSymbolsRunArgs;
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RESOLVE_SYMBOLS_USAGE = exports.RESOLVE_SYMBOLS_MAX_LIMIT = exports.RESOLVE_SYMBOLS_DEFAULT_LIMIT = void 0;
|
|
3
|
+
exports.RESOLVE_SYMBOLS_USAGE = exports.RESOLVE_SYMBOLS_ASSET_CLASSES = exports.RESOLVE_SYMBOLS_MAX_LIMIT = exports.RESOLVE_SYMBOLS_DEFAULT_LIMIT = void 0;
|
|
4
4
|
exports.parseResolveSymbolsArgs = parseResolveSymbolsArgs;
|
|
5
5
|
const errors_1 = require("./errors");
|
|
6
6
|
const exchanges_1 = require("./exchanges");
|
|
7
7
|
exports.RESOLVE_SYMBOLS_DEFAULT_LIMIT = 8;
|
|
8
8
|
exports.RESOLVE_SYMBOLS_MAX_LIMIT = 25;
|
|
9
|
+
exports.RESOLVE_SYMBOLS_ASSET_CLASSES = [
|
|
10
|
+
"all",
|
|
11
|
+
"equity_perp",
|
|
12
|
+
"rwa_perp",
|
|
13
|
+
"crypto",
|
|
14
|
+
];
|
|
9
15
|
exports.RESOLVE_SYMBOLS_USAGE = [
|
|
10
|
-
"alphafox resolve-symbols <query...> [--exchange binance] [--limit 8]",
|
|
16
|
+
"alphafox resolve-symbols <query...> [--exchange binance] [--asset-class all] [--limit 8]",
|
|
11
17
|
"alphafox resolve-symbols --query BTC --query ETH --exchange okx",
|
|
18
|
+
"alphafox resolve-symbols NVDA AAPL TSLA --exchange binance --asset-class equity_perp",
|
|
12
19
|
];
|
|
13
20
|
function usage(message, subtype = "invalid_args") {
|
|
14
21
|
throw new errors_1.ResolveSymbolsError({
|
|
@@ -30,6 +37,7 @@ function parseResolveSymbolsArgs(args) {
|
|
|
30
37
|
const queries = [];
|
|
31
38
|
let exchange = exchanges_1.RESOLVE_SYMBOLS_DEFAULT_EXCHANGE;
|
|
32
39
|
let limit = exports.RESOLVE_SYMBOLS_DEFAULT_LIMIT;
|
|
40
|
+
let assetClass = "all";
|
|
33
41
|
let help = false;
|
|
34
42
|
for (let i = 0; i < args.length; i += 1) {
|
|
35
43
|
const a = args[i];
|
|
@@ -59,6 +67,14 @@ function parseResolveSymbolsArgs(args) {
|
|
|
59
67
|
case "--exchange":
|
|
60
68
|
exchange = read();
|
|
61
69
|
break;
|
|
70
|
+
case "--asset-class": {
|
|
71
|
+
const value = read().trim().toLowerCase();
|
|
72
|
+
if (!exports.RESOLVE_SYMBOLS_ASSET_CLASSES.includes(value)) {
|
|
73
|
+
usage(`--asset-class must be ${exports.RESOLVE_SYMBOLS_ASSET_CLASSES.join("|")}`, "invalid_asset_class");
|
|
74
|
+
}
|
|
75
|
+
assetClass = value;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
62
78
|
case "--limit": {
|
|
63
79
|
const n = Number(read());
|
|
64
80
|
if (!Number.isInteger(n) || n <= 0 || n > exports.RESOLVE_SYMBOLS_MAX_LIMIT) {
|
|
@@ -72,7 +88,7 @@ function parseResolveSymbolsArgs(args) {
|
|
|
72
88
|
}
|
|
73
89
|
}
|
|
74
90
|
if (help) {
|
|
75
|
-
return { help: true, queries: [], exchange, limit };
|
|
91
|
+
return { help: true, queries: [], exchange, limit, assetClass };
|
|
76
92
|
}
|
|
77
93
|
const normalizedQueries = queries.map((item) => item.trim()).filter(Boolean);
|
|
78
94
|
if (normalizedQueries.length === 0) {
|
|
@@ -90,6 +106,7 @@ function parseResolveSymbolsArgs(args) {
|
|
|
90
106
|
queries: uniqueQueries(normalizedQueries),
|
|
91
107
|
exchange: resolvedExchange,
|
|
92
108
|
limit,
|
|
109
|
+
assetClass,
|
|
93
110
|
};
|
|
94
111
|
}
|
|
95
112
|
function uniqueQueries(queries) {
|
|
@@ -41,10 +41,12 @@ function resolveSymbolsHelpData() {
|
|
|
41
41
|
name: "resolve-symbols",
|
|
42
42
|
usage: parse_args_1.RESOLVE_SYMBOLS_USAGE,
|
|
43
43
|
notes: [
|
|
44
|
-
"Resolves user-mentioned tickers against
|
|
45
|
-
"Default --exchange is binance (binance_perp_usdt).
|
|
46
|
-
"
|
|
47
|
-
"
|
|
44
|
+
"Resolves user-mentioned tickers against market.symbols.list for the chosen catalog",
|
|
45
|
+
"Default --exchange is binance (binance_perp_usdt). Built-in aliases: binance|okx|bybit|bitget|hyperliquid|aster",
|
|
46
|
+
"US stock perps live in the same catalog (NVDA/USDT:USDT) and are tagged symbolMetadata.assetClass=equity_perp / isTradFiRwa",
|
|
47
|
+
"For 美股 use --asset-class equity_perp. For gold/silver RWAs use rwa_perp. Crypto perps are untagged or --asset-class crypto",
|
|
48
|
+
"Each match includes assetClass and isTradFiRwa. Do not treat an equity_perp as a crypto coin",
|
|
49
|
+
"Catalog dump remains alphafox market symbols list --exchange <id>",
|
|
48
50
|
],
|
|
49
51
|
};
|
|
50
52
|
}
|
|
@@ -77,12 +79,22 @@ async function executeResolveSymbols(args, flags, env = process.env, deps = {})
|
|
|
77
79
|
details: res.json,
|
|
78
80
|
});
|
|
79
81
|
}
|
|
80
|
-
const
|
|
82
|
+
const payload = (0, catalog_1.extractMarketCatalog)(res.json);
|
|
83
|
+
const catalog = (0, match_1.indexCatalogSymbols)(payload.symbols, payload.symbolMetadata);
|
|
84
|
+
if (args.assetClass !== "all" &&
|
|
85
|
+
!catalog.some((item) => item.metadata?.assetClass)) {
|
|
86
|
+
throw new errors_1.ResolveSymbolsError({
|
|
87
|
+
type: "runtime",
|
|
88
|
+
subtype: "metadata_missing",
|
|
89
|
+
message: "market.symbols.list did not include symbolMetadata; cannot apply --asset-class",
|
|
90
|
+
hint: "Retry without --asset-class, or use a catalog that returns symbolMetadata.assetClass.",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
81
93
|
return {
|
|
82
94
|
exchange: exchange.id,
|
|
83
95
|
exchangeLabel: exchange.label,
|
|
84
96
|
catalogSize: catalog.length,
|
|
85
|
-
queries: args.queries.map((query) => (0, match_1.resolveQueryAgainstCatalog)(query, catalog, args.limit)),
|
|
97
|
+
queries: args.queries.map((query) => (0, match_1.resolveQueryAgainstCatalog)(query, catalog, args.limit, args.assetClass)),
|
|
86
98
|
};
|
|
87
99
|
}
|
|
88
100
|
async function cmdResolveSymbols(args, flags, env = process.env, deps = {}) {
|
|
@@ -119,6 +131,7 @@ async function cmdResolveSymbols(args, flags, env = process.env, deps = {}) {
|
|
|
119
131
|
path: (0, catalog_1.marketSymbolsPath)(exchange.id),
|
|
120
132
|
exchange: exchange.id,
|
|
121
133
|
exchangeLabel: exchange.label,
|
|
134
|
+
assetClass: parsed.assetClass,
|
|
122
135
|
queries: parsed.queries,
|
|
123
136
|
}, { format: flags.format, jq: flags.jq });
|
|
124
137
|
return 0;
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
export type ResolveSymbolsStatus = "exact" | "close" | "ambiguous" | "none";
|
|
2
|
+
export type ResolveAssetClassFilter = "all" | "equity_perp" | "rwa_perp" | "crypto";
|
|
3
|
+
export interface SymbolMetadata {
|
|
4
|
+
readonly isTradFiRwa?: boolean;
|
|
5
|
+
readonly assetClass?: string;
|
|
6
|
+
readonly minAmount?: number;
|
|
7
|
+
readonly minCost?: number;
|
|
8
|
+
readonly contractSize?: number;
|
|
9
|
+
}
|
|
2
10
|
export type ResolveSymbolsMatchReason = "exact_canonical" | "exact_compact" | "exact_pair" | "exact_base" | "prefix" | "contains" | "close";
|
|
3
11
|
export interface ResolveSymbolsMatch {
|
|
4
12
|
readonly symbol: string;
|
|
5
13
|
readonly reason: ResolveSymbolsMatchReason;
|
|
6
14
|
readonly score: number;
|
|
15
|
+
readonly assetClass: string | null;
|
|
16
|
+
readonly isTradFiRwa: boolean;
|
|
7
17
|
}
|
|
8
18
|
export interface ResolveSymbolsQueryResult {
|
|
9
19
|
readonly query: string;
|
|
10
20
|
readonly status: ResolveSymbolsStatus;
|
|
11
21
|
readonly resolved: string | null;
|
|
22
|
+
readonly assetClass: string | null;
|
|
23
|
+
readonly isTradFiRwa: boolean;
|
|
12
24
|
readonly needsConfirmation: boolean;
|
|
13
25
|
readonly matches: readonly ResolveSymbolsMatch[];
|
|
14
26
|
readonly matchCount: number;
|
|
@@ -24,6 +36,7 @@ export interface ResolveSymbolsRunArgs {
|
|
|
24
36
|
readonly queries: readonly string[];
|
|
25
37
|
readonly exchange: string;
|
|
26
38
|
readonly limit: number;
|
|
39
|
+
readonly assetClass: ResolveAssetClassFilter;
|
|
27
40
|
}
|
|
28
41
|
export interface CatalogSymbol {
|
|
29
42
|
readonly symbol: string;
|
|
@@ -34,4 +47,5 @@ export interface CatalogSymbol {
|
|
|
34
47
|
readonly searchKey: string;
|
|
35
48
|
readonly baseKey: string;
|
|
36
49
|
readonly compactKey: string;
|
|
50
|
+
readonly metadata?: SymbolMetadata;
|
|
37
51
|
}
|
|
@@ -1,141 +1,141 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "@alphafox/cli",
|
|
4
|
-
"packageVersion": "0.3.
|
|
4
|
+
"packageVersion": "0.3.7",
|
|
5
5
|
"contractVersion": "2026-08-13",
|
|
6
|
-
"bundleHash": "
|
|
6
|
+
"bundleHash": "e12e1922538778707e60e931a247ecebb3e028cefeba295f4ca299d8d82d661b",
|
|
7
7
|
"skills": [
|
|
8
8
|
{
|
|
9
9
|
"name": "alphafox",
|
|
10
|
-
"version": "0.3.
|
|
10
|
+
"version": "0.3.7",
|
|
11
11
|
"files": [
|
|
12
12
|
{
|
|
13
13
|
"path": "SKILL.md",
|
|
14
|
-
"sha256": "
|
|
15
|
-
"size":
|
|
14
|
+
"sha256": "2cd53898008075e68afd8ce955b63cf61f2971ef28f6c13c41853b1c5de967c8",
|
|
15
|
+
"size": 3553
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
|
-
"hash": "
|
|
18
|
+
"hash": "d687ecf8cc366e26dcb535bf31a30faceb037f021c818fa24997d144a22d3c20"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"name": "alphafox-account",
|
|
22
|
-
"version": "0.3.
|
|
22
|
+
"version": "0.3.7",
|
|
23
23
|
"files": [
|
|
24
24
|
{
|
|
25
25
|
"path": "SKILL.md",
|
|
26
|
-
"sha256": "
|
|
26
|
+
"sha256": "fc5675dc44494227679994b761ca2e014d36acc207c68e3fb6d833912a7644ee",
|
|
27
27
|
"size": 783
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
|
-
"hash": "
|
|
30
|
+
"hash": "bc1352e9d352f313f69f5257ba351137778c3ee1d8714d2d80fc39c0824c5cec"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"name": "alphafox-admin",
|
|
34
|
-
"version": "0.3.
|
|
34
|
+
"version": "0.3.7",
|
|
35
35
|
"files": [
|
|
36
36
|
{
|
|
37
37
|
"path": "SKILL.md",
|
|
38
|
-
"sha256": "
|
|
38
|
+
"sha256": "6594e6cbfd319a41ae3abf9bf4f8239bb42bc25e6eec295999fe39cd694b2b8b",
|
|
39
39
|
"size": 787
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
|
-
"hash": "
|
|
42
|
+
"hash": "d6c5573444a020f376d51a73d44f39da9de8ea20bfd160f838b0de01bbb5e798"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"name": "alphafox-auth",
|
|
46
|
-
"version": "0.3.
|
|
46
|
+
"version": "0.3.7",
|
|
47
47
|
"files": [
|
|
48
48
|
{
|
|
49
49
|
"path": "SKILL.md",
|
|
50
|
-
"sha256": "
|
|
50
|
+
"sha256": "b7b2694cbcf6e784d89943950435cb34454309cfbe07e383cc028a435dfec77d",
|
|
51
51
|
"size": 1919
|
|
52
52
|
}
|
|
53
53
|
],
|
|
54
|
-
"hash": "
|
|
54
|
+
"hash": "aa7e2a39058660c4c803ed6e1bed94da0559aa943998336d6f0c83d8930a1d9d"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
"name": "alphafox-engine-backtest",
|
|
58
|
-
"version": "0.3.
|
|
58
|
+
"version": "0.3.7",
|
|
59
59
|
"files": [
|
|
60
60
|
{
|
|
61
61
|
"path": "SKILL.md",
|
|
62
|
-
"sha256": "
|
|
63
|
-
"size":
|
|
62
|
+
"sha256": "e09e938c9dd90d0be156b2d8bd83ba854c4d1a190a1b4aa575ca67db70184ebc",
|
|
63
|
+
"size": 7584
|
|
64
64
|
}
|
|
65
65
|
],
|
|
66
|
-
"hash": "
|
|
66
|
+
"hash": "91de2131ffde0b9fef16221d5589a8c430ae48ddfc4f2dc781d510b9d4c90532"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"name": "alphafox-exchange",
|
|
70
|
-
"version": "0.3.
|
|
70
|
+
"version": "0.3.7",
|
|
71
71
|
"files": [
|
|
72
72
|
{
|
|
73
73
|
"path": "SKILL.md",
|
|
74
|
-
"sha256": "
|
|
74
|
+
"sha256": "53cba327c5507266b4dca7193fad67ba33c0c7bb745be41fd194425b9ef5928e",
|
|
75
75
|
"size": 743
|
|
76
76
|
}
|
|
77
77
|
],
|
|
78
|
-
"hash": "
|
|
78
|
+
"hash": "910f451fc7939926cfbeee27ee72f2aae86fcdd78f343e9f02c30df105ac6480"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"name": "alphafox-market",
|
|
82
|
-
"version": "0.3.
|
|
82
|
+
"version": "0.3.7",
|
|
83
83
|
"files": [
|
|
84
84
|
{
|
|
85
85
|
"path": "SKILL.md",
|
|
86
|
-
"sha256": "
|
|
87
|
-
"size":
|
|
86
|
+
"sha256": "6589628478dc9c98c20479a2ffdded4014ce71b9c488dd386a606fef25a37d26",
|
|
87
|
+
"size": 3078
|
|
88
88
|
}
|
|
89
89
|
],
|
|
90
|
-
"hash": "
|
|
90
|
+
"hash": "84d243b7c53c519cba34c8c487ba23eae60bde8440c4dcfff06e20efd63c07fa"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"name": "alphafox-notification",
|
|
94
|
-
"version": "0.3.
|
|
94
|
+
"version": "0.3.7",
|
|
95
95
|
"files": [
|
|
96
96
|
{
|
|
97
97
|
"path": "SKILL.md",
|
|
98
|
-
"sha256": "
|
|
98
|
+
"sha256": "8b985ff7f33696eb11427147cd021d32654f525eea54f8098f368e8750a59381",
|
|
99
99
|
"size": 698
|
|
100
100
|
}
|
|
101
101
|
],
|
|
102
|
-
"hash": "
|
|
102
|
+
"hash": "1f316dc3fe251699b3f90102cbc16cb4fbd3a3c5c07b923297c075fe2e73a4b3"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
"name": "alphafox-shared",
|
|
106
|
-
"version": "0.3.
|
|
106
|
+
"version": "0.3.7",
|
|
107
107
|
"files": [
|
|
108
108
|
{
|
|
109
109
|
"path": "SKILL.md",
|
|
110
|
-
"sha256": "
|
|
111
|
-
"size":
|
|
110
|
+
"sha256": "3aac1ab46a759a2c6748516936f886ec028e680bff7deb3ff1abc51af99ed18a",
|
|
111
|
+
"size": 5163
|
|
112
112
|
}
|
|
113
113
|
],
|
|
114
|
-
"hash": "
|
|
114
|
+
"hash": "72a7255ab23ff7c1adf41b1ff2e22834d1b58ee9e2ccea990c64f9277bf8b0a3"
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"name": "alphafox-strategy",
|
|
118
|
-
"version": "0.3.
|
|
118
|
+
"version": "0.3.7",
|
|
119
119
|
"files": [
|
|
120
120
|
{
|
|
121
121
|
"path": "SKILL.md",
|
|
122
|
-
"sha256": "
|
|
123
|
-
"size":
|
|
122
|
+
"sha256": "1ef2a00dd1c74922a3d0248041813609fc58701e7857bb069cbed511b0c46168",
|
|
123
|
+
"size": 1826
|
|
124
124
|
}
|
|
125
125
|
],
|
|
126
|
-
"hash": "
|
|
126
|
+
"hash": "44c2bf74ff053977f3a8631115ebf868af7cff33856e0c6a4fe55080049c1ae1"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"name": "alphafox-trading",
|
|
130
|
-
"version": "0.3.
|
|
130
|
+
"version": "0.3.7",
|
|
131
131
|
"files": [
|
|
132
132
|
{
|
|
133
133
|
"path": "SKILL.md",
|
|
134
|
-
"sha256": "
|
|
135
|
-
"size":
|
|
134
|
+
"sha256": "db065fcc272e66d091cfe7469317d7911946f96094f475f64d34d201c392424c",
|
|
135
|
+
"size": 3122
|
|
136
136
|
}
|
|
137
137
|
],
|
|
138
|
-
"hash": "
|
|
138
|
+
"hash": "af36dc51e47ca91cb4a2f5ca78e03e17f003ee47b5354cef42947f401fbe48c0"
|
|
139
139
|
}
|
|
140
140
|
]
|
|
141
141
|
}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CLI_CONTRACT_VERSION = exports.CLI_VERSION = exports.CLI_PACKAGE = exports.CLI_NAME = void 0;
|
|
4
4
|
exports.CLI_NAME = "alphafox";
|
|
5
5
|
exports.CLI_PACKAGE = "@alphafox/cli";
|
|
6
|
-
exports.CLI_VERSION = "0.3.
|
|
6
|
+
exports.CLI_VERSION = "0.3.7";
|
|
7
7
|
var operations_1 = require("./catalog/operations");
|
|
8
8
|
Object.defineProperty(exports, "CLI_CONTRACT_VERSION", { enumerable: true, get: function () { return operations_1.CATALOG_VERSION; } });
|
package/package.json
CHANGED
package/skills/account/SKILL.md
CHANGED
package/skills/admin/SKILL.md
CHANGED
package/skills/alphafox/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox
|
|
3
|
-
description: AlphaFox CLI entry router. Use for any AlphaFox request — install, update, login, whoami, 回测, engine backtest, strategy
|
|
4
|
-
version: 0.3.
|
|
3
|
+
description: AlphaFox CLI entry router. Use for any AlphaFox request — install, update, login, whoami, 回测, engine backtest, strategy definitions, create/list/start/stop a running strategy (trader), ticker/标的 resolve (美股 or crypto), market data, exchange connectors, wallet, subscriptions, notifications, or admin. If a CLI command prints `[alphafox] update available`, ask the user「检测到新的版本,是否需要我帮你升级?」and only then run `alphafox update --format json --no-input`. Start here, then open the routed domain skill. Do not guess alphafox-engine-backtest vs alphafox-strategy vs alphafox-trading from memory.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# AlphaFox
|
|
@@ -10,7 +10,9 @@ This skill only routes. After choosing a row, **read that skill's `SKILL.md` and
|
|
|
10
10
|
|
|
11
11
|
Also read `alphafox-shared` before any CLI invocation (envelope, auth, risk, schema-first writes). Always `--format json --no-input`. Never `--token`.
|
|
12
12
|
|
|
13
|
-
Human-mentioned tickers go through `alphafox-market` (`alphafox resolve-symbols`) **before** they enter config, backtest, or writes.
|
|
13
|
+
Human-mentioned tickers go through `alphafox-market` (`alphafox resolve-symbols`) **before** they enter config, backtest, or writes. Keep the operator's asset class (美股 → `equity_perp` on `binance_perp_usdt`).
|
|
14
|
+
|
|
15
|
+
A **trader** is a running strategy instance (paper or live), not a person. Creating a strategy means creating a trader.
|
|
14
16
|
|
|
15
17
|
## Route
|
|
16
18
|
|
|
@@ -18,23 +20,23 @@ Human-mentioned tickers go through `alphafox-market` (`alphafox resolve-symbols`
|
|
|
18
20
|
|---|---|
|
|
19
21
|
| Install, update, Skills status/sync, doctor, version, catalog, how to call the CLI | `alphafox-shared` |
|
|
20
22
|
| Login, logout, whoami, profile, staging vs production | `alphafox-auth` |
|
|
21
|
-
|
|
|
23
|
+
| Ticker / 标的 / 美股 / crypto / resolve a misspelled symbol | `alphafox-market` |
|
|
22
24
|
| Engine WASM backtest, experiment, `engine-backtest run`, persist a local run | `alphafox-engine-backtest` |
|
|
23
|
-
| Strategy
|
|
24
|
-
|
|
|
25
|
+
| Strategy types / definitions / validate config (grid, dca, copy, …) | `alphafox-strategy` |
|
|
26
|
+
| Create, list, start, or stop a running strategy (trader), including copy | `alphafox-trading` |
|
|
25
27
|
| Exchange connectors | `alphafox-exchange` |
|
|
26
28
|
| Account, wallet, subscription | `alphafox-account` |
|
|
27
29
|
| Notification channels | `alphafox-notification` |
|
|
28
30
|
| Admin-only operations | `alphafox-admin` |
|
|
29
31
|
|
|
30
|
-
If several rows apply, load **all** of them (typical: `alphafox-shared` + `alphafox-market` + one domain skill).
|
|
32
|
+
If several rows apply, load **all** of them (typical: `alphafox-shared` + `alphafox-market` + one domain skill). “帮我建一个网格/DCA/跟单策略” → `alphafox-strategy` (pick the definition) **and** `alphafox-trading` (create the trader).
|
|
31
33
|
|
|
32
34
|
## Upgrade reminder
|
|
33
35
|
|
|
34
36
|
The CLI may print this on **stderr** at most once every 24 hours:
|
|
35
37
|
|
|
36
38
|
```text
|
|
37
|
-
[alphafox] update available: 0.3.
|
|
39
|
+
[alphafox] update available: 0.3.6 -> 0.3.7. After the user confirms, run: alphafox update --format json --no-input,
|
|
38
40
|
```
|
|
39
41
|
|
|
40
42
|
If you see that notice (or `updateAvailable: true` from `alphafox update --check`):
|
|
@@ -55,6 +57,6 @@ Do not install Skills from GitHub. Details and dry-run / check commands live in
|
|
|
55
57
|
|
|
56
58
|
- Local Engine tape + wasm + optional persist → `alphafox-engine-backtest` (`alphafox engine-backtest run`, hyphen).
|
|
57
59
|
- Experiment catalog CRUD → same skill, underscore catalog `engine_backtest.*`.
|
|
58
|
-
-
|
|
60
|
+
- Web `/api/v1/backtests` (`backtests.*`) is **not** a CLI surface. Do not call it via typed commands, `schema`, or `alphafox api`.
|
|
59
61
|
|
|
60
62
|
Ambiguous “帮我回测” → `alphafox-engine-backtest`, after resolving symbols.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-shared
|
|
3
3
|
description: Shared AlphaFox CLI rules for Agents — auth, profiles, envelopes, risk gates, and public operationIds only.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# AlphaFox shared Agent contract
|
|
@@ -76,7 +76,7 @@ Wrong environment / missing permission / missing `--yes`: stop. Do not retry wit
|
|
|
76
76
|
|
|
77
77
|
## Commands
|
|
78
78
|
|
|
79
|
-
User-mentioned tickers (including typos) must be resolved with `alphafox resolve-symbols` before they are written into config. See `skills/market`.
|
|
79
|
+
User-mentioned tickers (including typos) must be resolved with `alphafox resolve-symbols` before they are written into config. See `skills/market`. 美股 are `equity_perp` on `binance_perp_usdt`; do not swap them for a crypto coin.
|
|
80
80
|
|
|
81
81
|
1. Prefer typed catalog: `alphafox schema <operationId>` then invoke domain commands.
|
|
82
82
|
2. Raw escape hatch only for allowlisted facade:
|
|
@@ -104,7 +104,7 @@ Uncataloged writes cannot carry a non-empty body. Find the `operationId` first.
|
|
|
104
104
|
## Risk
|
|
105
105
|
|
|
106
106
|
- `high-risk-write` and uncataloged mutations (`unknown`) require `--yes` (exit code `10` if missing).
|
|
107
|
-
- Prefer `--dry-run` first for trader start/stop, withdrawals, admin writes.
|
|
107
|
+
- Prefer `--dry-run` first for trader create/start/stop, withdrawals, admin writes.
|
|
108
108
|
- Never auto-retry unknown write outcomes.
|
|
109
109
|
- CLI `--yes` is UX only; the server still enforces role, ownership, and scopes.
|
|
110
110
|
|
package/skills/auth/SKILL.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-engine-backtest
|
|
3
3
|
description: Local Engine WASM backtest (alphafox engine-backtest run|sweep) vs catalog experiment CRUD.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Engine Backtest
|
|
8
8
|
|
|
9
9
|
Always `--format json --no-input` (or `--format jsonl` when you need progress). Never `--token`. Tokens live in the OS keychain via `alphafox auth login`.
|
|
10
10
|
|
|
11
|
-
Human-mentioned tickers must be resolved with `alphafox resolve-symbols` (`skills/market`) before they go into `--config`. Use `data.queries[].resolved` only when `status` is `exact`, or `close` after confirming with the human.
|
|
11
|
+
Human-mentioned tickers must be resolved with `alphafox resolve-symbols` (`skills/market`) before they go into `--config`. Use `data.queries[].resolved` only when `status` is `exact`, or `close` after confirming with the human, and only when `assetClass` matches the operator (美股 → `equity_perp`). Local Engine tape is Binance-style USDT-M perps (`binance|okx|bybit|bitget|hyperliquid`), which is the same catalog that lists equity perps. Aster is in the public catalog but is **not** an Engine tape source. Do not rewrite `NVDA/USDT:USDT` into a crypto coin to force a backtest.
|
|
12
12
|
|
|
13
13
|
## Which command
|
|
14
14
|
|
|
15
15
|
| Intent | Use | Do not |
|
|
16
16
|
|---|---|---|
|
|
17
17
|
| Iterate a strategy locally (pull tape + run wasm + optional persist) | `alphafox engine-backtest run` (hyphen, built-in) | Do not treat this as server-side execution of `engine_backtest.experiments.byId.runs.create` |
|
|
18
|
-
| Local parameter search with explicit axes; persist one Sweep after completion | `alphafox engine-backtest sweep` | Never loop `runs.create` per coordinate. Do not call
|
|
18
|
+
| Local parameter search with explicit axes; persist one Sweep after completion | `alphafox engine-backtest sweep` | Never loop `runs.create` per coordinate. Do not call `backtests.*` |
|
|
19
19
|
| Local search with zero writes | `alphafox engine-backtest sweep ... --no-persist` | Do not persist a cancelled or incomplete search |
|
|
20
20
|
| List / get / delete persisted Sweeps | Catalog `engine_backtest.experiments.byId.sweeps.*` | Do not invent a second catalog. Delete is high-risk and needs `--yes` |
|
|
21
21
|
| List / get / create / rename / delete experiments and persisted runs | Catalog `engine_backtest.*` (underscore) | Do not invent a second catalog |
|
|
22
|
-
|
|
|
22
|
+
| Web `/api/v1/backtests` job | — | Not a CLI surface. Do not call `backtests.*` or `/api/v1/backtests` |
|
|
23
23
|
|
|
24
24
|
Read the create-experiment body with `alphafox schema` **before** composing JSON. Do not invent experiment fields. Large create/run/sweep payloads use `--config @file`, never a guessed `--body`.
|
|
25
25
|
|
|
@@ -110,4 +110,4 @@ Owner isolation and 7-day expiry are enforced by the server. Applying a coordina
|
|
|
110
110
|
- `engine_backtest.experiments.byId.sweeps.byId.get`
|
|
111
111
|
- High-risk (not this skill's run/sweep path): `engine_backtest.experiments.byId.update` / `.byId.delete` / `.byId.runs.byId.delete` / `.byId.sweeps.byId.delete`
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
`backtests.*` is not an Engine Sweep or Engine Run surface. Do not call it from this skill.
|
package/skills/exchange/SKILL.md
CHANGED
package/skills/market/SKILL.md
CHANGED
|
@@ -1,33 +1,53 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-market
|
|
3
|
-
description: Market data
|
|
4
|
-
version: 0.3.
|
|
3
|
+
description: Market data and ticker resolution for US equity perps, RWAs, and crypto on the same perp catalog. Use when the user names 美股, NVDA, AAPL, BTC, or any 标的. Keep the operator's asset class via symbolMetadata — do not rewrite NVDA into a crypto coin.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Market
|
|
8
8
|
|
|
9
9
|
Always `--format json --no-input`. Prefer readonly scopes. No mock success if upstream fails.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Asset class first
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Binance US stocks are **equity perps in the same** `binance_perp_usdt` catalog (`NVDA/USDT:USDT`). They are not a second exchange. `symbolMetadata` tags them:
|
|
14
|
+
|
|
15
|
+
| Tag | Meaning |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `assetClass: "equity_perp"` and `isTradFiRwa: true` | US stock perp (NVDA, AAPL, TSLA) |
|
|
18
|
+
| `assetClass: "rwa_perp"` and `isTradFiRwa: true` | TradFi RWA perp (XAU, XAG) |
|
|
19
|
+
| untagged / not TradFi | Crypto perp (BTC, ETH) |
|
|
20
|
+
|
|
21
|
+
| Operator said | Resolve with |
|
|
22
|
+
|---|---|
|
|
23
|
+
| 美股 / US stocks / 持仓 / NVDA the company | `--exchange binance --asset-class equity_perp` |
|
|
24
|
+
| 黄金 / 白银 / RWA | `--exchange binance --asset-class rwa_perp` |
|
|
25
|
+
| BTC / ETH / 加密永续 | `--exchange binance` or `--asset-class crypto` |
|
|
26
|
+
|
|
27
|
+
`NVDA/USDT:USDT` with `equity_perp` **is** the US stock product. Do not replace it with a different crypto base.
|
|
28
|
+
|
|
29
|
+
## Resolve tickers
|
|
30
|
+
|
|
31
|
+
Whenever a human mentions a stock, coin, ticker, or contract — including typos — resolve it **before** putting a symbol into strategy config, backtest, trader settings, or any write.
|
|
14
32
|
|
|
15
33
|
```bash
|
|
16
|
-
alphafox resolve-symbols BTC ETH
|
|
34
|
+
alphafox resolve-symbols BTC ETH --exchange binance --format json --no-input
|
|
35
|
+
alphafox resolve-symbols NVDA AAPL TSLA --exchange binance --asset-class equity_perp --format json --no-input
|
|
17
36
|
```
|
|
18
37
|
|
|
19
38
|
- Default `--exchange` is Binance (`binance_perp_usdt`). Aliases: `binance|okx|bybit|bitget|hyperliquid|aster`.
|
|
20
|
-
- This built-in loads
|
|
21
|
-
- Read `data.queries[]`. `resolved` is a
|
|
39
|
+
- This built-in loads `GET /api/v1/market/symbols?exchange=...` (includes `symbolMetadata`) and matches locally. Do not invent a symbol from memory. Do not pull a second ccxt universe.
|
|
40
|
+
- Read `data.queries[]`. `resolved` is a catalog id such as `NVDA/USDT:USDT` or `BTC/USDT:USDT`. Also read `assetClass` and `isTradFiRwa` on the query and on `matches[]`.
|
|
41
|
+
- `matchCount` is the full hit count; `matches` may be capped by `--limit`.
|
|
22
42
|
|
|
23
43
|
| `status` | Agent action |
|
|
24
44
|
|---|---|
|
|
25
|
-
| `exact` | Use `resolved
|
|
26
|
-
| `close` | One near match already in `resolved`.
|
|
27
|
-
| `ambiguous` | `resolved` is null. Show `matches[].symbol` and ask the human to pick. Do not pick. |
|
|
28
|
-
| `none` | Stop. Ask
|
|
45
|
+
| `exact` | Use `resolved` when `assetClass` matches the operator (美股 → `equity_perp`). |
|
|
46
|
+
| `close` | One near match already in `resolved`. Confirm with the human, and confirm the asset class. |
|
|
47
|
+
| `ambiguous` | `resolved` is null. Show `matches[].symbol` plus `assetClass` and ask the human to pick. Do not pick. |
|
|
48
|
+
| `none` | Stop. Ask for another ticker. Do not invent a symbol and do not swap in a crypto coin. |
|
|
29
49
|
|
|
30
|
-
Do not treat `close` as exact. Do not retry a failed resolve as a different
|
|
50
|
+
Do not treat `close` as exact. Do not retry a failed equity resolve as a different crypto base.
|
|
31
51
|
|
|
32
52
|
Raw catalog dump (no matching):
|
|
33
53
|
|
package/skills/strategy/SKILL.md
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-strategy
|
|
3
|
-
description: Strategy definitions and
|
|
4
|
-
version: 0.3.
|
|
3
|
+
description: Strategy definitions — list types (grid, dca, copy, …) and validate config. Creating a running strategy is creating a trader; use alphafox-trading for that.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Strategy
|
|
7
|
+
# Strategy definitions
|
|
8
8
|
|
|
9
|
-
Always `--format json --no-input`. Read scopes `trading:read`;
|
|
9
|
+
Always `--format json --no-input`. Read scopes `trading:read`; validate is `trading:write`.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
A **definition** is a strategy type (grid, dca, copy, …). A **trader** is one running instance of a definition. Instantiating a definition is `alphafox-trading`, not this skill.
|
|
12
|
+
|
|
13
|
+
Whenever the human names a ticker (US stock, coin, or contract), resolve it with `alphafox resolve-symbols` (`skills/market`) before writing symbols into a config you later validate or hand to create. 美股 are equity perps in `binance_perp_usdt` (`NVDA/USDT:USDT`, `assetClass=equity_perp`) — do not swap them for a crypto coin.
|
|
12
14
|
|
|
13
15
|
## Read
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
18
|
alphafox schema trading.strategy_definitions.list --format json --no-input
|
|
17
19
|
alphafox api GET /api/v1/trading/strategy-definitions --format json --no-input
|
|
20
|
+
alphafox trading strategy_definitions byId get --definitionId <id> --format json --no-input
|
|
18
21
|
```
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
Use the list to pick the definition the operator named. Copy / rebate-copy / DCA / grid are rows in this catalog, not a separate product.
|
|
24
|
+
|
|
25
|
+
## Validate config
|
|
21
26
|
|
|
22
|
-
Read `request.body` first. Do not invent
|
|
27
|
+
Read `request.body` first. Do not invent definition or config fields.
|
|
23
28
|
|
|
24
29
|
```bash
|
|
25
|
-
alphafox schema
|
|
26
|
-
alphafox
|
|
27
|
-
# large / nested bodies:
|
|
28
|
-
# alphafox chats create --config @./create-chat.json --format json --no-input
|
|
30
|
+
alphafox schema trading.strategy_definitions.byId.validate_config --format json --no-input
|
|
31
|
+
alphafox trading strategy_definitions byId validate_config --definitionId <id> --config @./strategy-config.json --format json --no-input
|
|
29
32
|
```
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Engine strategy backtest (WASM tape + persist) is `skills/engine-backtest` (`alphafox engine-backtest run`). Chat-attached `/api/v1/backtests` (`backtests.*`) is not a CLI surface — do not call it.
|
|
34
|
+
After the config validates, create the running instance with `alphafox-trading`.
|
|
34
35
|
|
|
35
36
|
## operationIds
|
|
36
37
|
|
|
37
38
|
- `trading.strategy_definitions.list`
|
|
38
|
-
- `
|
|
39
|
+
- `trading.strategy_definitions.byId.get`
|
|
40
|
+
- `trading.strategy_definitions.byId.validate_config`
|
package/skills/trading/SKILL.md
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-trading
|
|
3
|
-
description:
|
|
4
|
-
version: 0.3.
|
|
3
|
+
description: Running strategies (traders) — create, list, start, and stop. A trader is a live or paper strategy instance (grid, dca, copy, …), not a person.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# Running strategies (traders)
|
|
8
8
|
|
|
9
|
-
Always `--format json --no-input`. Read first.
|
|
9
|
+
Always `--format json --no-input`. Read first. Creates and updates need `trading:write`; start/stop also `trading:high-risk`.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
A **trader** is a running strategy instance (paper or live). Creating a strategy means creating a trader. Bind it to a **strategy definition**, an exchange connector, and runtime settings.
|
|
12
|
+
|
|
13
|
+
Human-mentioned tickers must be resolved with `alphafox resolve-symbols` (`skills/market`) before they are written into trader config. 美股 stay `equity_perp` contracts such as `NVDA/USDT:USDT`.
|
|
14
|
+
|
|
15
|
+
Pick the create operation from the definition the operator asked for:
|
|
16
|
+
|
|
17
|
+
| Kind | Create |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Engine definitions (grid, dca, …) | `trading.traders.create` |
|
|
20
|
+
| Hyperliquid copy | `trading.hl_copy_traders.create` |
|
|
21
|
+
| Rebate copy | `trading.rebate_copy_traders.create` |
|
|
22
|
+
|
|
23
|
+
Copy leads come from `trading.signal_sources.list` when the operator named one. Same trader lifecycle (list / start / stop) after create.
|
|
12
24
|
|
|
13
25
|
## Read
|
|
14
26
|
|
|
@@ -16,9 +28,23 @@ Human-mentioned tickers must be resolved with `alphafox resolve-symbols` (`skill
|
|
|
16
28
|
alphafox api GET /api/v1/trading/traders --format json --no-input
|
|
17
29
|
```
|
|
18
30
|
|
|
19
|
-
##
|
|
31
|
+
## Create
|
|
32
|
+
|
|
33
|
+
Read `alphafox schema <operationId>` first. Body may only include documented `request.body` fields. Large / nested bodies use `--config @file`.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
alphafox schema trading.traders.create --format json --no-input
|
|
37
|
+
alphafox trading traders create --config @./create-trader.json --dry-run --format json --no-input
|
|
38
|
+
alphafox trading traders create --config @./create-trader.json --yes --format json --no-input
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`trading.traders.create` is `high-risk-write` and needs `--yes`. Copy creates follow whatever `risk` the schema reports — `--dry-run` first, then `--yes` when required.
|
|
42
|
+
|
|
43
|
+
If a required field is missing, re-read the schema and ask the operator. Do not invent ids. The CLI has no authoring-session surface; instantiate from a definition, connector, and config.
|
|
44
|
+
|
|
45
|
+
## High-risk start / stop
|
|
20
46
|
|
|
21
|
-
Read `alphafox schema trading.traders.byId.start` first. Body may only include documented fields (`reason` is optional).
|
|
47
|
+
Read `alphafox schema trading.traders.byId.start` first. Body may only include documented fields (`reason` is optional).
|
|
22
48
|
|
|
23
49
|
```bash
|
|
24
50
|
alphafox schema trading.traders.byId.start --format json --no-input
|
|
@@ -39,5 +65,9 @@ Stop: `POST /api/v1/trading/traders/{traderId}/stop` with the same `--dry-run` t
|
|
|
39
65
|
## operationIds
|
|
40
66
|
|
|
41
67
|
- `trading.traders.list`
|
|
68
|
+
- `trading.traders.create`
|
|
69
|
+
- `trading.hl_copy_traders.create`
|
|
70
|
+
- `trading.rebate_copy_traders.create`
|
|
71
|
+
- `trading.signal_sources.list`
|
|
42
72
|
- `trading.traders.byId.start`
|
|
43
73
|
- `trading.traders.byId.stop`
|