@alphafox/cli 0.1.5 → 0.3.2

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.
Files changed (104) hide show
  1. package/README.md +42 -4
  2. package/dist/auth/browser-login.d.ts +30 -0
  3. package/dist/auth/browser-login.js +193 -0
  4. package/dist/auth/loopback-callback.d.ts +32 -0
  5. package/dist/auth/loopback-callback.js +175 -0
  6. package/dist/auth/open-browser.d.ts +15 -0
  7. package/dist/auth/open-browser.js +54 -0
  8. package/dist/auth/refresh.d.ts +27 -2
  9. package/dist/auth/refresh.js +52 -15
  10. package/dist/catalog/allowlist.d.ts +20 -4
  11. package/dist/catalog/allowlist.js +126 -25
  12. package/dist/catalog/command-tree.d.ts +35 -0
  13. package/dist/catalog/command-tree.js +119 -0
  14. package/dist/catalog/compatibility.d.ts +23 -0
  15. package/dist/catalog/compatibility.js +58 -0
  16. package/dist/catalog/generated/registry.json +6137 -0
  17. package/dist/catalog/generated/schemas.json +31036 -0
  18. package/dist/catalog/operations.d.ts +76 -3
  19. package/dist/catalog/operations.js +87 -213
  20. package/dist/catalog/validate-body.d.ts +22 -0
  21. package/dist/catalog/validate-body.js +98 -0
  22. package/dist/commands/request-body.d.ts +21 -0
  23. package/dist/commands/request-body.js +92 -0
  24. package/dist/commands/run.js +283 -162
  25. package/dist/config/profiles.js +3 -3
  26. package/dist/engine-backtest/errors.d.ts +18 -0
  27. package/dist/engine-backtest/errors.js +26 -0
  28. package/dist/engine-backtest/fetch-runtime.d.ts +38 -0
  29. package/dist/engine-backtest/fetch-runtime.js +170 -0
  30. package/dist/engine-backtest/native-import.d.ts +1 -0
  31. package/dist/engine-backtest/native-import.js +10 -0
  32. package/dist/engine-backtest/parse-args.d.ts +6 -0
  33. package/dist/engine-backtest/parse-args.js +281 -0
  34. package/dist/engine-backtest/persist.d.ts +32 -0
  35. package/dist/engine-backtest/persist.js +94 -0
  36. package/dist/engine-backtest/replay-timeframe.d.ts +16 -0
  37. package/dist/engine-backtest/replay-timeframe.js +48 -0
  38. package/dist/engine-backtest/resolve-packages.d.ts +27 -0
  39. package/dist/engine-backtest/resolve-packages.js +288 -0
  40. package/dist/engine-backtest/run-command.d.ts +38 -0
  41. package/dist/engine-backtest/run-command.js +540 -0
  42. package/dist/engine-backtest/types.d.ts +249 -0
  43. package/dist/engine-backtest/types.js +2 -0
  44. package/dist/envelope.d.ts +3 -0
  45. package/dist/envelope.js +43 -3
  46. package/dist/http/client.js +18 -15
  47. package/dist/index.d.ts +16 -5
  48. package/dist/index.js +47 -1
  49. package/dist/install/exec.d.ts +13 -0
  50. package/dist/install/exec.js +73 -0
  51. package/dist/install/package-root.d.ts +4 -0
  52. package/dist/install/package-root.js +59 -0
  53. package/dist/install/types.d.ts +69 -0
  54. package/dist/install/types.js +26 -0
  55. package/dist/install/wizard.d.ts +21 -0
  56. package/dist/install/wizard.js +332 -0
  57. package/dist/keychain/linux-secret-service.d.ts +11 -0
  58. package/dist/keychain/linux-secret-service.js +93 -0
  59. package/dist/keychain/store.d.ts +20 -1
  60. package/dist/keychain/store.js +94 -6
  61. package/dist/keychain/windows-credential.d.ts +13 -0
  62. package/dist/keychain/windows-credential.js +176 -0
  63. package/dist/safety/confirmation.d.ts +10 -3
  64. package/dist/safety/confirmation.js +27 -4
  65. package/dist/version.d.ts +2 -2
  66. package/dist/version.js +3 -2
  67. package/docs/.nojekyll +0 -0
  68. package/docs/agents/domain.md +51 -0
  69. package/docs/agents/issue-tracker.md +156 -0
  70. package/docs/agents/triage-labels.md +18 -0
  71. package/docs/alphafox-cli-installation-guide.md +105 -0
  72. package/docs/e2e-staging.md +76 -6
  73. package/docs/favicon.svg +4 -0
  74. package/docs/index.html +748 -0
  75. package/docs/logo/alphafox-mark.svg +4 -0
  76. package/docs/logo/alphafox-wordmark-black-en.svg +17 -0
  77. package/docs/logo/alphafox-wordmark-white-en.svg +16 -0
  78. package/docs/release-supply-chain.md +107 -26
  79. package/package.json +10 -3
  80. package/skills/account/SKILL.md +8 -6
  81. package/skills/admin/SKILL.md +9 -4
  82. package/skills/alphafox-shared/SKILL.md +44 -14
  83. package/skills/auth/SKILL.md +21 -6
  84. package/skills/engine-backtest/SKILL.md +71 -0
  85. package/skills/exchange/SKILL.md +10 -3
  86. package/skills/market/SKILL.md +9 -4
  87. package/skills/notification/SKILL.md +8 -3
  88. package/skills/strategy/SKILL.md +23 -9
  89. package/skills/trading/SKILL.md +18 -5
  90. package/vendor/backtest-runner/NOTICE.md +1 -0
  91. package/vendor/backtest-runner/README.md +97 -0
  92. package/vendor/backtest-runner/index.d.ts +423 -0
  93. package/vendor/backtest-runner/index.mjs +59 -0
  94. package/vendor/backtest-runner/lib/abortable.mjs +23 -0
  95. package/vendor/backtest-runner/lib/cache.mjs +159 -0
  96. package/vendor/backtest-runner/lib/coverage.mjs +238 -0
  97. package/vendor/backtest-runner/lib/encode.mjs +28 -0
  98. package/vendor/backtest-runner/lib/exchanges.mjs +143 -0
  99. package/vendor/backtest-runner/lib/proxy.mjs +78 -0
  100. package/vendor/backtest-runner/lib/scenario.mjs +66 -0
  101. package/vendor/backtest-runner/lib/series.mjs +370 -0
  102. package/vendor/backtest-runner/lib/tape-loader.mjs +614 -0
  103. package/vendor/backtest-runner/lib/timeframes.mjs +55 -0
  104. package/vendor/backtest-runner/package.json +13 -0
@@ -1,35 +1,49 @@
1
1
  ---
2
2
  name: alphafox-strategy
3
3
  description: Strategy definitions, chats, and backtests via public operationIds.
4
- version: 0.1.0
4
+ version: 0.3.2
5
5
  ---
6
6
 
7
7
  # Strategy / Chat / Backtest
8
8
 
9
+ Always `--format json --no-input`. Read scopes `trading:read` / `backtests:read`; writes `chats:write` / `backtests:write`.
10
+
9
11
  ## Read
10
12
 
11
13
  ```bash
12
- alphafox schema trading.strategy_definitions.list
13
- alphafox api GET /api/v1/trading/strategy-definitions
14
+ alphafox schema trading.strategy_definitions.list --format json --no-input
15
+ alphafox api GET /api/v1/trading/strategy-definitions --format json --no-input
14
16
  ```
15
17
 
16
18
  ## Write (ordinary)
17
19
 
20
+ Read `request.body` first. Do not invent chat or strategy fields.
21
+
18
22
  ```bash
19
- alphafox api POST /api/v1/chats --body '{"strategyGenerationMode":"simple"}'
23
+ alphafox schema chats.create --format json --no-input
24
+ alphafox chats create --body '{"strategyGenerationMode":"simple"}' --format json --no-input
25
+ # large / nested bodies:
26
+ # alphafox chats create --config @./create-chat.json --format json --no-input
20
27
  ```
21
28
 
22
- Requires auth. Sends `Idempotency-Key` when available.
29
+ Requires auth. Sends `Idempotency-Key` when available. Duplicate key → `409`; do not invent a new key unless the operator asks to create another chat.
30
+
31
+ Engine strategy backtest (WASM tape + persist) is `skills/engine-backtest` (`alphafox engine-backtest run`). Do not treat `/api/v1/backtests` as the Engine WASM runner — that stub is the chat backtest job below.
23
32
 
24
33
  ## Long-running backtest
25
34
 
26
35
  ```bash
27
- alphafox api POST /api/v1/backtests --body '{...}'
28
- alphafox api GET /api/v1/backtests/{backtestId}
29
- alphafox api GET /api/v1/backtests/{backtestId}/stream
30
- alphafox api POST /api/v1/backtests/{backtestId}/cancel --body '{}'
36
+ alphafox schema backtests.create --format json --no-input
37
+ alphafox api POST /api/v1/backtests --body '{"chatId":"<chat-id>"}' --format json --no-input
38
+ alphafox api GET /api/v1/backtests/{backtestId} --format json --no-input
39
+ alphafox api GET /api/v1/backtests/{backtestId}/stream --format jsonl --no-input
40
+ alphafox api POST /api/v1/backtests/{backtestId}/cancel --body '{}' --format json --no-input
31
41
  ```
32
42
 
43
+ `backtests.create` requires `chatId`. `strategyId` is optional: the facade resolves a compiled strategy on that chat. A chat with no compiled strategy returns `CHAT_HAS_NO_COMPILED_STRATEGY` (not `JOB_NOT_FOUND`). Optional `backtestSettings` overlays chat settings when it is a settingsJson object.
44
+
45
+ If the stream drops, `GET` the backtest by id — do not assume success. Cancel is explicit; interruption must remain queryable.
46
+
33
47
  ## operationIds
34
48
 
35
49
  - `trading.strategy_definitions.list`
@@ -1,25 +1,38 @@
1
1
  ---
2
2
  name: alphafox-trading
3
3
  description: Traders list and high-risk start/stop with confirmation gates.
4
- version: 0.1.0
4
+ version: 0.3.2
5
5
  ---
6
6
 
7
7
  # Trading
8
8
 
9
+ Always `--format json --no-input`. Read first. Writes need scopes `trading:write`; start/stop also `trading:high-risk`.
10
+
9
11
  ## Read
10
12
 
11
13
  ```bash
12
- alphafox api GET /api/v1/trading/traders
14
+ alphafox api GET /api/v1/trading/traders --format json --no-input
13
15
  ```
14
16
 
15
17
  ## High-risk write
16
18
 
19
+ Read `alphafox schema trading.traders.byId.start` first. Body may only include documented fields (`reason` is optional). Do not invent keys.
20
+
17
21
  ```bash
18
- alphafox api POST /api/v1/trading/traders/{traderId}/start --body '{}' --dry-run
19
- alphafox api POST /api/v1/trading/traders/{traderId}/start --body '{}' --yes
22
+ alphafox schema trading.traders.byId.start --format json --no-input
23
+ alphafox trading traders byId start --traderId <id> --body '{}' --dry-run --format json --no-input
24
+ alphafox trading traders byId start --traderId <id> --body '{}' --yes --format json --no-input
20
25
  ```
21
26
 
22
- Without `--yes`, CLI exits `10` with `confirmation_required`.
27
+ Without `--yes`, CLI exits `10` with `confirmation_required`. Server still checks role/ownership.
28
+
29
+ Stop: `POST /api/v1/trading/traders/{traderId}/stop` with the same `--dry-run` then `--yes` sequence.
30
+
31
+ ## Recovery
32
+
33
+ - `403`: missing scope or not owner — stop, do not retry `--yes`.
34
+ - `409`: trader already in the requested state — report, do not loop start/stop.
35
+ - Unknown HTTP after a write: do not auto-retry.
23
36
 
24
37
  ## operationIds
25
38
 
@@ -0,0 +1 @@
1
+ Vendored from alphafox-engine `npm/backtest-runner` so public CLI installs do not need GitHub Packages. Keep this copy aligned when the Engine runner changes.
@@ -0,0 +1,97 @@
1
+ # Vendored Engine tape runner
2
+
3
+ This directory is copied from `alphafox-engine/npm/backtest-runner` so the public CLI does not need GitHub Packages. Keep it aligned when the Engine runner changes.
4
+
5
+ # @alphafoxai/backtest-runner
6
+
7
+ Node 侧的 Engine Backtest **tape loader + scenario 组装**库。从交易所拉 closed OHLCV / funding,编成 wasm 运行时需要的 tape JSON 与列式 `ArrayBuffer`,并套上与 web 回测相同的默认 `executionModel`。
8
+
9
+ 本包**不执行 wasm**,也不依赖 `@alphafoxai/backtest-wasm`(避免把约 40MB 的 wasm 拖进 CLI 的懒加载路径)。CLI 应同时依赖本包与 wasm 包:runner 负责行情,wasm 包负责 `planBacktest` / `runBacktest`。
10
+
11
+ ## 安装
12
+
13
+ ```bash
14
+ npm install @alphafoxai/backtest-runner --registry=https://npm.pkg.github.com
15
+ ```
16
+
17
+ 要求 Node >= 20。
18
+
19
+ ## 发布
20
+
21
+ `main` push 通过常规 CI 后,仅当 `lib/`、入口 / 类型声明或 package 元数据发生变化时发布到 GitHub Packages。测试、README 或其他 Engine 文件单独变化不会触发 runner 发布。CI 使用当前 workflow run / attempt 生成唯一版本,并通过仓库 `GITHUB_TOKEN` 发布。
22
+
23
+ ## 公共 API
24
+
25
+ ```js
26
+ import {
27
+ DEFAULT_EXECUTION_MODEL,
28
+ TAPE_EXCHANGES,
29
+ resolveTapeExchange,
30
+ encodeOhlcvColumns,
31
+ createFileTapeCache,
32
+ loadTape,
33
+ assembleScenario,
34
+ } from "@alphafoxai/backtest-runner";
35
+
36
+ const { tape, buffers, coverageWarnings } = await loadTape({
37
+ exchangeId: "binance_perp_usdt",
38
+ symbols: ["BTC/USDT:USDT"],
39
+ timeframes: ["1m", "1h"],
40
+ fromMs,
41
+ toMs,
42
+ dataQualityMode: "strict",
43
+ });
44
+
45
+ const scenario = assembleScenario({
46
+ runId,
47
+ definitionId: "grid",
48
+ configSchemaVersion: 4,
49
+ config,
50
+ subscriptionTier: "pro",
51
+ initialEquity: 10_000,
52
+ traderName: "paper-grid",
53
+ tape,
54
+ });
55
+ ```
56
+
57
+ | 导出 | 作用 |
58
+ |---|---|
59
+ | `DEFAULT_EXECUTION_MODEL` | web 硬编码值:`ohlc_path_4` / maker `0.0002` / taker `0.0005` / slippage `0.0001` |
60
+ | `TAPE_EXCHANGES` | Binance / OKX / Bybit / Bitget / Hyperliquid 线性合约定义 |
61
+ | `resolveTapeExchange(id)` | 解析 `binance_perp_usdt` 或 `binance` 等别名;未知 id **抛错** |
62
+ | `encodeOhlcvColumns(rows)` | 与 wasm 包相同的 float64 列式小端布局 |
63
+ | `createFileTapeCache(rootDir)` | 默认根目录 `~/.alphafox/cache/engine-backtest` |
64
+ | `loadTape(request, options?)` | 拉数 + 缓存缺口补齐 + 覆盖率校验 |
65
+ | `assembleScenario(input)` | 组装 `EngineBacktestScenario`,不跑 wasm |
66
+
67
+ `loadTape` 可注入 `ohlcvFetcher` / `fundingFetcher` / `marketsLoader`,单测不得打真实交易所。任一注入器出现时,本包拒绝再构造 live ccxt client。
68
+
69
+ ## 缓存
70
+
71
+ - 语义对齐 web 的 closed-series IndexedDB 缓存:每个 `ccxtId + symbol + timeframe` 一条滚动区间,命中后只补缺口。
72
+ - Node 侧改为文件系统 JSON;max-age 30 天。
73
+ - `options.cache === false` / `"disable"` 关闭缓存;`options.cacheDir` 覆盖根目录。测试应使用临时目录。
74
+
75
+ ## 代理
76
+
77
+ 尊重 `HTTPS_PROXY` / `https_proxy` / `HTTP_PROXY` / `http_proxy`,并写入 ccxt 构造参数 `httpsProxy` / `httpProxy`。也可显式传入 `options.httpsProxy` / `options.httpProxy` / `options.agent`。未配置时不会假装“已走代理”。
78
+
79
+ ## 分页 limit
80
+
81
+ 与 web `tape-loader.series.ts` 对齐:Binance 1500、OKX 100、Bybit / Bitget 1000、Hyperliquid 5000。Bitget 另受约 89 天请求跨度限制;Hyperliquid 分页带 `until` 窗口。
82
+
83
+ ## 数据质量
84
+
85
+ - `strict`(默认):任何缺口 / 缺数 / 非法 K 线都抛 `TapeDataUnavailableError`。
86
+ - `basic`:硬失败(缺市场、空序列、非法 K 线、拉数失败)仍抛错;软缺口进入 `coverageWarnings`。
87
+ - 禁止 mock 成功或静默降级。
88
+
89
+ ## 已知限制(相对 alphafox-web)
90
+
91
+ - **不执行 wasm**,不做 `planBacktest` / `runBacktest`。
92
+ - **HIP-3**:构造 Hyperliquid 时与 web 一样只附加硬编码的 `xyz` builder DEX,不拉取完整 HIP-3 目录,也不移植 Next alias / 浏览器 HIP-3 市场列表。原生 HL USDC 线性合约是主路径;HIP-3 符号属于尽力而为。
93
+ - **缓存后端**是文件系统,不是 IndexedDB;key 版本仍是 `closed-series-v2`。
94
+ - **未知交易所 id 抛错**,web 的 `resolveEngineBacktestTapeExchange` 会静默回落到 Binance。
95
+ - **Aster / Gate** 不是 tape 数据源。
96
+ - Hyperliquid 不提供 `6h` K 线(与 web 相同,快速失败)。
97
+ - 本包不依赖 `@alphafoxai/backtest-wasm`;`encodeOhlcvColumns` 与必要类型自包含。`EngineBacktestTapeMarket.precisionMode` 按 Go tape 协议写出(wasm 包的 `index.d.ts` 目前漏了该字段)。
@@ -0,0 +1,423 @@
1
+ export const TAPE_SERIES_COLUMNS: readonly string[];
2
+
3
+ export function encodeOhlcvColumns(
4
+ rows: ReadonlyArray<readonly [number, number, number, number, number, number]>
5
+ ): ArrayBuffer;
6
+
7
+ export const DEFAULT_EXECUTION_MODEL: {
8
+ readonly pricePath: "ohlc_path_4";
9
+ readonly makerFeeRate: 0.0002;
10
+ readonly takerFeeRate: 0.0005;
11
+ readonly slippageRate: 0.0001;
12
+ };
13
+
14
+ export type TapeQuoteAsset = "USDT" | "USDC";
15
+ export type TapeCcxtId =
16
+ | "binanceusdm"
17
+ | "okx"
18
+ | "bybit"
19
+ | "bitget"
20
+ | "hyperliquid";
21
+ export type TapeExchangeId =
22
+ | "binance_perp_usdt"
23
+ | "okx_perp_usdt"
24
+ | "bybit_perp_usdt"
25
+ | "bitget_perp_usdt"
26
+ | "hyperliquid_perp_usdc";
27
+
28
+ export interface TapeExchangeDefinition {
29
+ readonly id: TapeExchangeId | string;
30
+ readonly label: string;
31
+ readonly ccxtId: TapeCcxtId | string;
32
+ readonly marketType: "swap";
33
+ readonly quoteAsset: TapeQuoteAsset;
34
+ }
35
+
36
+ export const TAPE_EXCHANGES: readonly TapeExchangeDefinition[];
37
+ export const PUBLIC_MARKET_EXCHANGE_BINANCE: "binance_perp_usdt";
38
+ export const PUBLIC_MARKET_EXCHANGE_OKX: "okx_perp_usdt";
39
+ export const PUBLIC_MARKET_EXCHANGE_BYBIT: "bybit_perp_usdt";
40
+ export const PUBLIC_MARKET_EXCHANGE_BITGET: "bitget_perp_usdt";
41
+ export const PUBLIC_MARKET_EXCHANGE_HYPERLIQUID: "hyperliquid_perp_usdc";
42
+ export const HYPERLIQUID_PUBLIC_MARKET_DEXES: readonly string[];
43
+
44
+ export function resolveTapeExchange(
45
+ exchangeId: string | TapeExchangeDefinition
46
+ ): TapeExchangeDefinition;
47
+
48
+ export interface TapeExchangeRuntimeConfig {
49
+ readonly ohlcvPageLimit: number;
50
+ readonly fundingPageLimit: number;
51
+ readonly requestParams: Readonly<Record<string, unknown>>;
52
+ readonly constructorOptions?: Readonly<Record<string, unknown>>;
53
+ readonly unsupportedTimeframes?: readonly string[];
54
+ }
55
+
56
+ export function tapeExchangeRuntimeConfig(
57
+ exchange: TapeExchangeDefinition
58
+ ): TapeExchangeRuntimeConfig;
59
+
60
+ export const DEFAULT_TAPE_CACHE_DIR: string;
61
+ export const CACHE_KEY_VERSION: "closed-series-v2";
62
+ export const CACHE_MAX_AGE_MS: number;
63
+
64
+ export type CachedOhlcvRow = readonly [
65
+ number,
66
+ number,
67
+ number,
68
+ number,
69
+ number,
70
+ number,
71
+ ];
72
+
73
+ export interface CachedOhlcvRange {
74
+ readonly sinceMs: number;
75
+ readonly untilMs: number;
76
+ readonly rows: CachedOhlcvRow[];
77
+ }
78
+
79
+ export interface OhlcvRangeSegment {
80
+ readonly sinceMs: number;
81
+ readonly untilMs: number;
82
+ }
83
+
84
+ export interface FileTapeCache {
85
+ readonly disabled: boolean;
86
+ readonly rootDir?: string;
87
+ read(key: string): Promise<CachedOhlcvRange | null>;
88
+ write(key: string, range: CachedOhlcvRange): Promise<void>;
89
+ }
90
+
91
+ export function ohlcvSeriesCacheKey(
92
+ exchangeId: string,
93
+ symbol: string,
94
+ timeframe: string
95
+ ): string;
96
+ export function missingCachedOhlcvRanges(
97
+ cached: CachedOhlcvRange | null,
98
+ sinceMs: number,
99
+ untilMs: number
100
+ ): OhlcvRangeSegment[];
101
+ export function mergeCachedOhlcvRanges(
102
+ cached: CachedOhlcvRange | null,
103
+ addition: CachedOhlcvRange
104
+ ): CachedOhlcvRange;
105
+ export function createFileTapeCache(
106
+ rootDir?: string,
107
+ options?: { maxAgeMs?: number; nowMs?: number }
108
+ ): FileTapeCache;
109
+ export function createDisabledTapeCache(): FileTapeCache;
110
+
111
+ export type TapeDataQualityMode = "strict" | "basic";
112
+ export type TapeDataIssueCode =
113
+ | "market_missing"
114
+ | "ohlcv_missing"
115
+ | "invalid_ohlcv"
116
+ | "non_monotonic"
117
+ | "internal_gap"
118
+ | "prefix_gap"
119
+ | "suffix_gap"
120
+ | "warmup_insufficient"
121
+ | "load_failed"
122
+ | "coverage_insufficient";
123
+
124
+ export interface TapeDataIssue {
125
+ readonly code: TapeDataIssueCode;
126
+ readonly symbol: string;
127
+ readonly timeframe: string;
128
+ readonly expected?: number;
129
+ readonly actual?: number;
130
+ readonly timestamp?: number;
131
+ readonly message?: string;
132
+ }
133
+
134
+ export class TapeDataUnavailableError extends Error {
135
+ readonly issues: readonly TapeDataIssue[];
136
+ constructor(issues: readonly TapeDataIssue[]);
137
+ }
138
+
139
+ export function isTapeDataUnavailableError(
140
+ value: unknown
141
+ ): value is TapeDataUnavailableError;
142
+
143
+ export type EngineBacktestPrecisionMode = "DECIMAL_PLACES" | "TICK_SIZE";
144
+ export type EngineBacktestSubscriptionTier = "free" | "pro" | "pro_max";
145
+ export type EngineBacktestPricePath = "ohlc_path_4" | "close_only";
146
+
147
+ export interface EngineBacktestExecutionModel {
148
+ readonly pricePath: EngineBacktestPricePath;
149
+ readonly makerFeeRate: number;
150
+ readonly takerFeeRate: number;
151
+ readonly slippageRate: number;
152
+ }
153
+
154
+ export interface EngineBacktestTapeMarket {
155
+ readonly id: string;
156
+ readonly symbol: string;
157
+ readonly base?: string;
158
+ readonly quote?: string;
159
+ readonly settle?: string;
160
+ readonly contractSize: number;
161
+ readonly linear: boolean;
162
+ readonly precisionMode: EngineBacktestPrecisionMode;
163
+ readonly precisionAmount?: number;
164
+ readonly precisionPrice?: number;
165
+ readonly amountMin?: number;
166
+ readonly amountMax?: number;
167
+ readonly priceMin?: number;
168
+ readonly costMin?: number;
169
+ }
170
+
171
+ export interface EngineBacktestTapeSeriesRef {
172
+ readonly symbol: string;
173
+ readonly timeframe: string;
174
+ readonly buffer: string;
175
+ readonly rows: number;
176
+ }
177
+
178
+ export interface EngineBacktestFundingSample {
179
+ readonly timestamp: number;
180
+ readonly rate: number;
181
+ readonly interval: string;
182
+ }
183
+
184
+ export interface EngineBacktestTapeInput {
185
+ readonly from: string;
186
+ readonly to: string;
187
+ readonly baseTimeframe: string;
188
+ readonly markets: Readonly<Record<string, EngineBacktestTapeMarket>>;
189
+ readonly series: readonly EngineBacktestTapeSeriesRef[];
190
+ readonly fundingRates?: Readonly<
191
+ Record<string, readonly EngineBacktestFundingSample[]>
192
+ >;
193
+ readonly lowLiquiditySymbols?: readonly string[];
194
+ }
195
+
196
+ export interface EngineBacktestScenarioTrader {
197
+ readonly id?: string;
198
+ readonly name?: string;
199
+ readonly strategyDefinitionId: string;
200
+ readonly configSchemaVersion: number;
201
+ readonly subscriptionTier: EngineBacktestSubscriptionTier;
202
+ readonly config: unknown;
203
+ }
204
+
205
+ export interface EngineBacktestScenario {
206
+ readonly version: 1;
207
+ readonly runId: string;
208
+ readonly trader: EngineBacktestScenarioTrader;
209
+ readonly exchange: {
210
+ readonly positionSideDual: boolean;
211
+ readonly initialEquity: number;
212
+ };
213
+ readonly executionModel: EngineBacktestExecutionModel;
214
+ readonly tape: EngineBacktestTapeInput;
215
+ }
216
+
217
+ export interface EngineBacktestSeriesRequirement {
218
+ readonly symbol: string;
219
+ readonly timeframe: string;
220
+ readonly minWarmupCandles: number;
221
+ }
222
+
223
+ export interface EngineBacktestAuxiliaryDataRequirement {
224
+ readonly kind: string;
225
+ readonly parameters?: Record<string, unknown>;
226
+ }
227
+
228
+ export interface TapeLoadProgress {
229
+ readonly stage: "markets" | "ohlcv" | "validation";
230
+ readonly detail: string;
231
+ readonly fraction: number;
232
+ }
233
+
234
+ export interface TapeMarketsSnapshot {
235
+ readonly markets: Readonly<Record<string, TapeSymbolMarket>>;
236
+ readonly precisionMode?: number;
237
+ readonly nowMs?: number;
238
+ }
239
+
240
+ export interface TapeSymbolMarket {
241
+ readonly id?: string;
242
+ readonly symbol?: string;
243
+ readonly created?: number;
244
+ readonly base?: string;
245
+ readonly quote?: string;
246
+ readonly settle?: string;
247
+ readonly active?: boolean;
248
+ readonly type?: string;
249
+ readonly swap?: boolean;
250
+ readonly linear?: boolean;
251
+ readonly inverse?: boolean;
252
+ readonly contractSize?: number;
253
+ readonly precision?: { readonly amount?: number; readonly price?: number };
254
+ readonly limits?: {
255
+ readonly amount?: { readonly min?: number; readonly max?: number };
256
+ readonly price?: { readonly min?: number };
257
+ readonly cost?: { readonly min?: number };
258
+ };
259
+ }
260
+
261
+ export type TapeOhlcvFetcher = (
262
+ symbol: string,
263
+ timeframe: string,
264
+ since?: number,
265
+ limit?: number,
266
+ params?: Record<string, unknown>
267
+ ) => Promise<ReadonlyArray<readonly number[]>>;
268
+
269
+ export type TapeFundingFetcher = (
270
+ symbol: string,
271
+ since?: number,
272
+ limit?: number,
273
+ params?: Record<string, unknown>
274
+ ) => Promise<ReadonlyArray<{ timestamp?: number; fundingRate?: number }>>;
275
+
276
+ export interface TapeLoadRequest {
277
+ readonly exchangeId?: string;
278
+ readonly exchange?: TapeExchangeDefinition;
279
+ readonly symbols: readonly string[];
280
+ readonly baseTimeframe?: string;
281
+ readonly timeframes: readonly string[];
282
+ readonly seriesRequirements?: readonly EngineBacktestSeriesRequirement[];
283
+ readonly needsFunding?: boolean;
284
+ readonly auxiliaryDataRequirements?: readonly EngineBacktestAuxiliaryDataRequirement[];
285
+ readonly fromMs: number;
286
+ readonly toMs: number;
287
+ readonly dataQualityMode?: TapeDataQualityMode;
288
+ readonly signal?: AbortSignal;
289
+ readonly onProgress?: (progress: TapeLoadProgress) => void;
290
+ readonly nowMs?: number;
291
+ readonly ohlcvFetcher?: TapeOhlcvFetcher;
292
+ readonly fundingFetcher?: TapeFundingFetcher;
293
+ readonly marketsLoader?: () => Promise<TapeMarketsSnapshot>;
294
+ }
295
+
296
+ export interface TapeProxyOptions {
297
+ readonly httpsProxy?: string;
298
+ readonly httpProxy?: string;
299
+ readonly agent?: unknown;
300
+ }
301
+
302
+ export interface TapeLoadOptions extends TapeProxyOptions {
303
+ readonly cache?: FileTapeCache | false | "disable";
304
+ readonly cacheDir?: string;
305
+ readonly nowMs?: number;
306
+ readonly onProgress?: (progress: TapeLoadProgress) => void;
307
+ readonly createExchange?: (
308
+ exchange: TapeExchangeDefinition,
309
+ constructorOptions: Record<string, unknown>
310
+ ) => Promise<TapeRuntimeExchange> | TapeRuntimeExchange;
311
+ }
312
+
313
+ export interface TapeRuntimeExchange {
314
+ markets?: Readonly<Record<string, TapeSymbolMarket>>;
315
+ precisionMode?: number;
316
+ loadMarkets(): Promise<Readonly<Record<string, TapeSymbolMarket>>>;
317
+ fetchTime(): Promise<number>;
318
+ fetchOHLCV: TapeOhlcvFetcher;
319
+ fetchFundingRateHistory?: TapeFundingFetcher;
320
+ }
321
+
322
+ export interface TapeChartSeries {
323
+ readonly symbol: string;
324
+ readonly timeframe: string;
325
+ readonly rows: number;
326
+ readonly buffer: ArrayBuffer;
327
+ }
328
+
329
+ export interface TapeLoadResult {
330
+ readonly tape: EngineBacktestTapeInput;
331
+ readonly buffers: Record<string, ArrayBuffer>;
332
+ readonly coverageWarnings: readonly string[];
333
+ readonly chartData?: {
334
+ readonly exchangeId: string;
335
+ readonly series: readonly TapeChartSeries[];
336
+ };
337
+ }
338
+
339
+ export function loadTape(
340
+ request: TapeLoadRequest,
341
+ options?: TapeLoadOptions
342
+ ): Promise<TapeLoadResult>;
343
+
344
+ export interface AssembleScenarioInput {
345
+ readonly runId: string;
346
+ readonly definitionId: string;
347
+ readonly configSchemaVersion: number;
348
+ readonly config: unknown;
349
+ readonly subscriptionTier: EngineBacktestSubscriptionTier;
350
+ readonly initialEquity: number;
351
+ readonly traderName?: string;
352
+ readonly traderId?: string;
353
+ readonly tape?: EngineBacktestTapeInput;
354
+ readonly preparedTape?: { readonly tape: EngineBacktestTapeInput };
355
+ readonly prepared?: { readonly tape: EngineBacktestTapeInput };
356
+ readonly executionModel?: Partial<EngineBacktestExecutionModel>;
357
+ }
358
+
359
+ export function assembleScenario(
360
+ input: AssembleScenarioInput
361
+ ): EngineBacktestScenario;
362
+
363
+ export const TIMEFRAME_MS: Readonly<Record<string, number>>;
364
+ export const ENGINE_BACKTEST_BASE_TIMEFRAME: string;
365
+ export const ENGINE_BACKTEST_WARMUP_CANDLES: number;
366
+
367
+ export function resolvePlanBaseTimeframe(input: {
368
+ readonly baseTimeframe?: string | null;
369
+ readonly timeframes?: readonly string[] | null;
370
+ }): string;
371
+
372
+ export function abortable<T>(
373
+ operation: Promise<T>,
374
+ signal?: AbortSignal
375
+ ): Promise<T>;
376
+
377
+ export function resolveCcxtProxyOptions(
378
+ options?: TapeProxyOptions,
379
+ env?: NodeJS.ProcessEnv
380
+ ): { httpsProxy?: string; httpProxy?: string; agent?: unknown };
381
+
382
+ export function buildCcxtConstructorOptions(
383
+ exchange: TapeExchangeDefinition,
384
+ options?: TapeProxyOptions & { runtimeConfig?: TapeExchangeRuntimeConfig }
385
+ ): Record<string, unknown>;
386
+
387
+ export function isClosedCandle(
388
+ timestampMs: number,
389
+ timeframe: string,
390
+ toMs: number
391
+ ): boolean;
392
+
393
+ export function ohlcvSeriesStartMs(
394
+ fromMs: number,
395
+ timeframe: string,
396
+ market?: Pick<TapeSymbolMarket, "created">
397
+ ): number;
398
+
399
+ export function effectiveTapeEndMs(
400
+ requestedToMs: number,
401
+ nowMs?: number,
402
+ baseTimeframe?: string
403
+ ): number;
404
+
405
+ export function inferFundingIntervals(
406
+ samples: readonly Omit<EngineBacktestFundingSample, "interval">[]
407
+ ): EngineBacktestFundingSample[];
408
+
409
+ export function classifyTapeSymbolsForPreflight(
410
+ symbols: readonly string[],
411
+ markets: Readonly<Record<string, TapeSymbolMarket>>,
412
+ quoteAsset: TapeQuoteAsset
413
+ ): {
414
+ readonly availableSymbols: readonly string[];
415
+ readonly missingSymbols: readonly string[];
416
+ };
417
+
418
+ export function resolveEngineBacktestPrecisionMode(
419
+ precisionMode: number | undefined,
420
+ exchangeLabel: string
421
+ ): EngineBacktestPrecisionMode;
422
+
423
+ export function resolveTapeCache(options?: TapeLoadOptions): FileTapeCache;
@@ -0,0 +1,59 @@
1
+ export { TAPE_SERIES_COLUMNS, encodeOhlcvColumns } from "./lib/encode.mjs";
2
+ export {
3
+ DEFAULT_EXECUTION_MODEL,
4
+ assembleScenario,
5
+ } from "./lib/scenario.mjs";
6
+ export {
7
+ TAPE_EXCHANGES,
8
+ PUBLIC_MARKET_EXCHANGE_BINANCE,
9
+ PUBLIC_MARKET_EXCHANGE_OKX,
10
+ PUBLIC_MARKET_EXCHANGE_BYBIT,
11
+ PUBLIC_MARKET_EXCHANGE_BITGET,
12
+ PUBLIC_MARKET_EXCHANGE_HYPERLIQUID,
13
+ HYPERLIQUID_PUBLIC_MARKET_DEXES,
14
+ resolveTapeExchange,
15
+ tapeExchangeRuntimeConfig,
16
+ } from "./lib/exchanges.mjs";
17
+ export {
18
+ DEFAULT_TAPE_CACHE_DIR,
19
+ CACHE_KEY_VERSION,
20
+ CACHE_MAX_AGE_MS,
21
+ ohlcvSeriesCacheKey,
22
+ missingCachedOhlcvRanges,
23
+ mergeCachedOhlcvRanges,
24
+ createFileTapeCache,
25
+ createDisabledTapeCache,
26
+ } from "./lib/cache.mjs";
27
+ export {
28
+ TapeDataUnavailableError,
29
+ isTapeDataUnavailableError,
30
+ evaluateOhlcvCoverage,
31
+ analyzeOhlcvCoverage,
32
+ } from "./lib/coverage.mjs";
33
+ export {
34
+ TIMEFRAME_MS,
35
+ ENGINE_BACKTEST_BASE_TIMEFRAME,
36
+ ENGINE_BACKTEST_WARMUP_CANDLES,
37
+ resolvePlanBaseTimeframe,
38
+ } from "./lib/timeframes.mjs";
39
+ export {
40
+ abortable,
41
+ } from "./lib/abortable.mjs";
42
+ export {
43
+ resolveCcxtProxyOptions,
44
+ buildCcxtConstructorOptions,
45
+ } from "./lib/proxy.mjs";
46
+ export {
47
+ isClosedCandle,
48
+ ohlcvSeriesStartMs,
49
+ fetchClosedOhlcvRange,
50
+ loadSeriesWithCache,
51
+ } from "./lib/series.mjs";
52
+ export {
53
+ loadTape,
54
+ resolveTapeCache,
55
+ effectiveTapeEndMs,
56
+ inferFundingIntervals,
57
+ classifyTapeSymbolsForPreflight,
58
+ resolveEngineBacktestPrecisionMode,
59
+ } from "./lib/tape-loader.mjs";