@tradejs/infra 1.0.6 → 1.0.8
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/aiEndpoints.d.mts +10 -0
- package/dist/aiEndpoints.d.ts +10 -0
- package/dist/aiEndpoints.js +159 -0
- package/dist/aiEndpoints.mjs +12 -0
- package/dist/aiLanguages.d.mts +11 -0
- package/dist/aiLanguages.d.ts +11 -0
- package/dist/aiLanguages.js +71 -0
- package/dist/aiLanguages.mjs +12 -0
- package/dist/aiModels.d.mts +12 -0
- package/dist/aiModels.d.ts +12 -0
- package/dist/aiModels.js +272 -0
- package/dist/aiModels.mjs +17 -0
- package/dist/chunk-CCC7DX2T.mjs +44 -0
- package/dist/{chunk-EFARW5QE.mjs → chunk-DSTV67R5.mjs} +48 -0
- package/dist/chunk-DTCLZIBM.mjs +163 -0
- package/dist/chunk-XQ3YBULV.mjs +132 -0
- package/dist/ml.js +119 -0
- package/dist/ml.mjs +119 -0
- package/dist/redis.d.mts +17 -1
- package/dist/redis.d.ts +17 -1
- package/dist/redis.js +50 -0
- package/dist/redis.mjs +5 -1
- package/dist/timescale.d.mts +18 -7
- package/dist/timescale.d.ts +18 -7
- package/dist/timescale.js +142 -31
- package/dist/timescale.mjs +140 -31
- package/dist/userSettings.d.mts +8 -6
- package/dist/userSettings.d.ts +8 -6
- package/dist/userSettings.js +336 -4
- package/dist/userSettings.mjs +27 -5
- package/package.json +18 -3
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/redis.ts
|
|
2
|
+
import { randomBytes } from "crypto";
|
|
2
3
|
import Redis from "ioredis";
|
|
3
4
|
var TTL_1D = 86400;
|
|
5
|
+
var SCREENSHOT_TOKEN_TTL_SECONDS = 15 * 60;
|
|
4
6
|
var toJson = (value) => JSON.stringify(value);
|
|
5
7
|
var logger = {
|
|
6
8
|
log: (level, message, ...args) => {
|
|
@@ -256,6 +258,36 @@ var setData = async (key, data, options = {}) => {
|
|
|
256
258
|
}
|
|
257
259
|
}
|
|
258
260
|
};
|
|
261
|
+
var createScreenshotSessionToken = async (userName) => {
|
|
262
|
+
const token = randomBytes(24).toString("hex");
|
|
263
|
+
await setData(
|
|
264
|
+
redisKeys.screenshotSessionToken(token),
|
|
265
|
+
{
|
|
266
|
+
userName,
|
|
267
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
expire: SCREENSHOT_TOKEN_TTL_SECONDS
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
return token;
|
|
274
|
+
};
|
|
275
|
+
var consumeScreenshotSessionToken = async (token) => {
|
|
276
|
+
const normalizedToken = token.trim();
|
|
277
|
+
if (!normalizedToken) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
const key = redisKeys.screenshotSessionToken(normalizedToken);
|
|
281
|
+
const payload = await getData(
|
|
282
|
+
key,
|
|
283
|
+
null
|
|
284
|
+
);
|
|
285
|
+
if (!payload?.userName) {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
await delKey(key);
|
|
289
|
+
return payload.userName;
|
|
290
|
+
};
|
|
259
291
|
var redisKeys = {
|
|
260
292
|
users: () => "users:index:",
|
|
261
293
|
user: (userName) => `users:index:${userName}`,
|
|
@@ -270,14 +302,28 @@ var redisKeys = {
|
|
|
270
302
|
testOrders: (userName, strategyName, testName) => `users:${userName}:tests:${strategyName}:${testName}:orders`,
|
|
271
303
|
testConfig: (userName, strategyName, testName) => `users:${userName}:tests:${strategyName}:${testName}:config`,
|
|
272
304
|
testStat: (userName, strategyName, testName) => `users:${userName}:tests:${strategyName}:${testName}:stat`,
|
|
305
|
+
testSummaries: (userName) => `users:${userName}:tests:index:summary`,
|
|
273
306
|
cacheChunk: (userName, chunkId) => `users:${userName}:cache:tests:chunks:${chunkId}`,
|
|
274
307
|
cacheOrders: (userName, orderLogId) => `users:${userName}:cache:tests:orders:${orderLogId}`,
|
|
275
308
|
cachePositions: (userName, orderLogId) => `users:${userName}:cache:tests:positions:${orderLogId}`,
|
|
276
309
|
signal: (symbol, signalId) => `signals:${symbol}:${signalId}`,
|
|
277
310
|
signalsBySymbol: (symbol) => `signals:${symbol}:`,
|
|
278
311
|
storeSignal: (symbol, signalId) => `store:signals:${symbol}:${signalId}`,
|
|
312
|
+
runtimeSignals: (userName) => `users:${userName}:runtime:signals:`,
|
|
313
|
+
runtimeSignal: (userName, signalId) => `users:${userName}:runtime:signals:${signalId}`,
|
|
314
|
+
runtimeSignalEvaluations: (userName) => `users:${userName}:runtime:signal-evaluations:`,
|
|
315
|
+
runtimeSignalEvaluation: (userName, evaluationId) => `users:${userName}:runtime:signal-evaluations:${evaluationId}`,
|
|
316
|
+
runtimeTrades: (userName) => `users:${userName}:runtime:trade-records:`,
|
|
317
|
+
runtimeTrade: (userName, orderId) => `users:${userName}:runtime:trade-records:${orderId}`,
|
|
318
|
+
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
319
|
+
runtimeActiveTrade: (userName, symbol) => `users:${userName}:runtime:active-trades:${symbol}`,
|
|
320
|
+
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
279
321
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
322
|
+
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
280
323
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
|
324
|
+
researchRuns: (userName) => `users:${userName}:research:runs:`,
|
|
325
|
+
researchRun: (userName, runId) => `users:${userName}:research:runs:${runId}`,
|
|
326
|
+
researchLatestRun: (userName, strategyName) => `users:${userName}:research:latest:${strategyName}`,
|
|
281
327
|
mlSignalsByStrategy: (strategyName) => `ml:${strategyName}:signals:`,
|
|
282
328
|
mlSignals: () => "ml:",
|
|
283
329
|
mlSignal: (strategyName, signalId) => `ml:${strategyName}:signals:${signalId}`,
|
|
@@ -293,5 +339,7 @@ export {
|
|
|
293
339
|
RedisWriteBlockedError,
|
|
294
340
|
delKeyWithOptions,
|
|
295
341
|
setData,
|
|
342
|
+
createScreenshotSessionToken,
|
|
343
|
+
consumeScreenshotSessionToken,
|
|
296
344
|
redisKeys
|
|
297
345
|
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AI_CUSTOM_ENDPOINT_VALUE
|
|
3
|
+
} from "./chunk-XQ3YBULV.mjs";
|
|
4
|
+
|
|
5
|
+
// src/aiModels.ts
|
|
6
|
+
var AI_CUSTOM_MODEL_VALUE = "__custom_model__";
|
|
7
|
+
var OPENAI_ENDPOINT = "https://api.openai.com/v1";
|
|
8
|
+
var ANTHROPIC_ENDPOINT = "https://api.anthropic.com/v1";
|
|
9
|
+
var OPENROUTER_ENDPOINT = "https://openrouter.ai/api/v1";
|
|
10
|
+
var GEMINI_ENDPOINT = "https://generativelanguage.googleapis.com/v1beta/openai";
|
|
11
|
+
var TOGETHER_ENDPOINT = "https://api.together.xyz/v1";
|
|
12
|
+
var GROQ_ENDPOINT = "https://api.groq.com/openai/v1";
|
|
13
|
+
var XAI_ENDPOINT = "https://api.x.ai/v1";
|
|
14
|
+
var QWEN_INTL_ENDPOINT = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
|
15
|
+
var QWEN_CN_ENDPOINT = "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
|
16
|
+
var QWEN_US_ENDPOINT = "https://dashscope-us.aliyuncs.com/compatible-mode/v1";
|
|
17
|
+
var PERPLEXITY_ENDPOINT = "https://api.perplexity.ai";
|
|
18
|
+
var KIMI_ENDPOINT = "https://api.moonshot.ai/v1";
|
|
19
|
+
var PROXY_API_ENDPOINT = "https://openai.api.proxyapi.ru/v1";
|
|
20
|
+
var AI_MODEL_OPTIONS_BY_ENDPOINT = {
|
|
21
|
+
[OPENAI_ENDPOINT]: [
|
|
22
|
+
{ label: "GPT-5 mini", value: "gpt-5-mini" },
|
|
23
|
+
{ label: "GPT-5", value: "gpt-5" },
|
|
24
|
+
{ label: "GPT-5.2", value: "gpt-5.2" },
|
|
25
|
+
{ label: "GPT-4.1", value: "gpt-4.1" },
|
|
26
|
+
{ label: "GPT-4o", value: "gpt-4o" }
|
|
27
|
+
],
|
|
28
|
+
[ANTHROPIC_ENDPOINT]: [
|
|
29
|
+
{ label: "Claude Sonnet 4", value: "claude-sonnet-4-20250514" },
|
|
30
|
+
{ label: "Claude Opus 4.1", value: "claude-opus-4-1-20250805" },
|
|
31
|
+
{ label: "Claude Opus 4", value: "claude-opus-4-20250514" },
|
|
32
|
+
{ label: "Claude 3.7 Sonnet", value: "claude-3-7-sonnet-20250219" },
|
|
33
|
+
{ label: "Claude 3.5 Haiku", value: "claude-3-5-haiku-20241022" }
|
|
34
|
+
],
|
|
35
|
+
[OPENROUTER_ENDPOINT]: [
|
|
36
|
+
{ label: "OpenAI GPT-5", value: "openai/gpt-5" },
|
|
37
|
+
{ label: "Anthropic Claude Sonnet 4", value: "anthropic/claude-sonnet-4" },
|
|
38
|
+
{ label: "Google Gemini 2.5 Pro", value: "google/gemini-2.5-pro" },
|
|
39
|
+
{ label: "OpenAI GPT-5 mini", value: "openai/gpt-5-mini" },
|
|
40
|
+
{
|
|
41
|
+
label: "DeepSeek V3.1",
|
|
42
|
+
value: "deepseek/deepseek-chat-v3.1"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
[GEMINI_ENDPOINT]: [
|
|
46
|
+
{ label: "Gemini 2.5 Pro", value: "gemini-2.5-pro" },
|
|
47
|
+
{ label: "Gemini 2.5 Flash", value: "gemini-2.5-flash" },
|
|
48
|
+
{ label: "Gemini 2.5 Flash-Lite", value: "gemini-2.5-flash-lite" },
|
|
49
|
+
{ label: "Gemini 2.0 Flash", value: "gemini-2.0-flash" },
|
|
50
|
+
{ label: "Gemini 2.0 Flash-Lite", value: "gemini-2.0-flash-lite" }
|
|
51
|
+
],
|
|
52
|
+
[TOGETHER_ENDPOINT]: [
|
|
53
|
+
{ label: "DeepSeek V3.1", value: "deepseek-ai/DeepSeek-V3.1" },
|
|
54
|
+
{
|
|
55
|
+
label: "Qwen3 Coder 480B",
|
|
56
|
+
value: "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
label: "Llama 4 Maverick",
|
|
60
|
+
value: "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8"
|
|
61
|
+
},
|
|
62
|
+
{ label: "DeepSeek V3", value: "deepseek-ai/DeepSeek-V3" },
|
|
63
|
+
{
|
|
64
|
+
label: "Llama 3.3 70B Turbo",
|
|
65
|
+
value: "meta-llama/Llama-3.3-70B-Instruct-Turbo"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
[GROQ_ENDPOINT]: [
|
|
69
|
+
{ label: "GPT-OSS 120B", value: "openai/gpt-oss-120b" },
|
|
70
|
+
{
|
|
71
|
+
label: "Llama 4 Scout",
|
|
72
|
+
value: "meta-llama/llama-4-scout-17b-16e-instruct"
|
|
73
|
+
},
|
|
74
|
+
{ label: "Qwen3 32B", value: "qwen/qwen3-32b" },
|
|
75
|
+
{ label: "Llama 3.3 70B", value: "llama-3.3-70b-versatile" },
|
|
76
|
+
{ label: "Llama 3.1 8B Instant", value: "llama-3.1-8b-instant" }
|
|
77
|
+
],
|
|
78
|
+
[XAI_ENDPOINT]: [
|
|
79
|
+
{ label: "Grok 4 Fast Reasoning", value: "grok-4-fast-reasoning" },
|
|
80
|
+
{ label: "Grok 4 Fast Non-Reasoning", value: "grok-4-fast-non-reasoning" },
|
|
81
|
+
{ label: "Grok Code Fast 1", value: "grok-code-fast-1" },
|
|
82
|
+
{ label: "Grok 4", value: "grok-4-0709" },
|
|
83
|
+
{ label: "Grok 3 Mini", value: "grok-3-mini" }
|
|
84
|
+
],
|
|
85
|
+
[QWEN_INTL_ENDPOINT]: [
|
|
86
|
+
{ label: "Qwen Plus Latest", value: "qwen-plus-latest" },
|
|
87
|
+
{ label: "Qwen Turbo Latest", value: "qwen-turbo-latest" },
|
|
88
|
+
{ label: "Qwen Max Latest", value: "qwen-max-latest" },
|
|
89
|
+
{ label: "Qwen3 Coder Plus", value: "qwen3-coder-plus" },
|
|
90
|
+
{ label: "Qwen3 Coder Next", value: "qwen3-coder-next" }
|
|
91
|
+
],
|
|
92
|
+
[QWEN_CN_ENDPOINT]: [
|
|
93
|
+
{ label: "Qwen Plus Latest", value: "qwen-plus-latest" },
|
|
94
|
+
{ label: "Qwen Turbo Latest", value: "qwen-turbo-latest" },
|
|
95
|
+
{ label: "Qwen Max Latest", value: "qwen-max-latest" },
|
|
96
|
+
{ label: "Qwen3 Coder Plus", value: "qwen3-coder-plus" },
|
|
97
|
+
{ label: "Qwen3 Coder Next", value: "qwen3-coder-next" }
|
|
98
|
+
],
|
|
99
|
+
[QWEN_US_ENDPOINT]: [
|
|
100
|
+
{ label: "Qwen Plus Latest", value: "qwen-plus-latest" },
|
|
101
|
+
{ label: "Qwen Turbo Latest", value: "qwen-turbo-latest" },
|
|
102
|
+
{ label: "Qwen Max Latest", value: "qwen-max-latest" },
|
|
103
|
+
{ label: "Qwen3 Coder Plus", value: "qwen3-coder-plus" },
|
|
104
|
+
{ label: "Qwen3 Coder Next", value: "qwen3-coder-next" }
|
|
105
|
+
],
|
|
106
|
+
[PERPLEXITY_ENDPOINT]: [
|
|
107
|
+
{ label: "Sonar Pro", value: "sonar-pro" },
|
|
108
|
+
{ label: "Sonar", value: "sonar" },
|
|
109
|
+
{ label: "Sonar Reasoning Pro", value: "sonar-reasoning-pro" },
|
|
110
|
+
{ label: "Sonar Deep Research", value: "sonar-deep-research" }
|
|
111
|
+
],
|
|
112
|
+
[KIMI_ENDPOINT]: [
|
|
113
|
+
{ label: "Kimi K2.5", value: "kimi-k2.5" },
|
|
114
|
+
{ label: "Kimi K2 Thinking", value: "kimi-k2-thinking" },
|
|
115
|
+
{ label: "Kimi K2 Turbo Preview", value: "kimi-k2-turbo-preview" },
|
|
116
|
+
{ label: "Kimi K2 0905 Preview", value: "kimi-k2-0905-preview" },
|
|
117
|
+
{ label: "Kimi K2", value: "kimi-k2" }
|
|
118
|
+
],
|
|
119
|
+
[PROXY_API_ENDPOINT]: [
|
|
120
|
+
{
|
|
121
|
+
label: "Anthropic Claude Sonnet 4",
|
|
122
|
+
value: "anthropic/claude-sonnet-4-20250514"
|
|
123
|
+
},
|
|
124
|
+
{ label: "Gemini 2.5 Flash", value: "gemini/gemini-2.5-flash" },
|
|
125
|
+
{ label: "OpenAI GPT-5 mini", value: "openai/gpt-5-mini" },
|
|
126
|
+
{ label: "OpenAI GPT-4o", value: "openai/gpt-4o" },
|
|
127
|
+
{
|
|
128
|
+
label: "OpenRouter DeepSeek Chat V3.1",
|
|
129
|
+
value: "openrouter/deepseek/deepseek-chat-v3.1"
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
};
|
|
133
|
+
var DEFAULT_AI_MODEL_BY_ENDPOINT = Object.fromEntries(
|
|
134
|
+
Object.entries(AI_MODEL_OPTIONS_BY_ENDPOINT).map(([endpoint, options]) => [
|
|
135
|
+
endpoint,
|
|
136
|
+
options[0]?.value ?? ""
|
|
137
|
+
])
|
|
138
|
+
);
|
|
139
|
+
var normalizeModel = (value) => value.trim();
|
|
140
|
+
var getAiModelOptionsForEndpoint = (endpoint) => AI_MODEL_OPTIONS_BY_ENDPOINT[endpoint] ?? [];
|
|
141
|
+
var getDefaultAiModelForEndpoint = (endpoint) => DEFAULT_AI_MODEL_BY_ENDPOINT[endpoint] ?? "";
|
|
142
|
+
var normalizeAiModel = (value, endpoint) => {
|
|
143
|
+
if (typeof value === "string") {
|
|
144
|
+
const trimmed = normalizeModel(value);
|
|
145
|
+
if (trimmed) {
|
|
146
|
+
return trimmed;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return getDefaultAiModelForEndpoint(endpoint);
|
|
150
|
+
};
|
|
151
|
+
var isKnownAiModelForEndpoint = (value, endpoint) => getAiModelOptionsForEndpoint(endpoint).some(
|
|
152
|
+
(option) => option.value === normalizeAiModel(value, endpoint)
|
|
153
|
+
);
|
|
154
|
+
var hasPresetAiModelsForEndpoint = (endpoint) => getAiModelOptionsForEndpoint(endpoint).length > 0 && endpoint !== AI_CUSTOM_ENDPOINT_VALUE;
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
AI_CUSTOM_MODEL_VALUE,
|
|
158
|
+
getAiModelOptionsForEndpoint,
|
|
159
|
+
getDefaultAiModelForEndpoint,
|
|
160
|
+
normalizeAiModel,
|
|
161
|
+
isKnownAiModelForEndpoint,
|
|
162
|
+
hasPresetAiModelsForEndpoint
|
|
163
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// src/aiEndpoints.ts
|
|
2
|
+
var AI_CUSTOM_ENDPOINT_VALUE = "__custom__";
|
|
3
|
+
var AI_ENDPOINT_OPTIONS = [
|
|
4
|
+
{
|
|
5
|
+
label: "OpenAI",
|
|
6
|
+
value: "https://api.openai.com/v1"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
label: "Claude",
|
|
10
|
+
value: "https://api.anthropic.com/v1"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
label: "OpenRouter",
|
|
14
|
+
value: "https://openrouter.ai/api/v1"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
label: "Gemini",
|
|
18
|
+
value: "https://generativelanguage.googleapis.com/v1beta/openai"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
label: "Together AI",
|
|
22
|
+
value: "https://api.together.xyz/v1"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
label: "Groq",
|
|
26
|
+
value: "https://api.groq.com/openai/v1"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: "DeepInfra",
|
|
30
|
+
value: "https://api.deepinfra.com/v1/openai"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
label: "xAI",
|
|
34
|
+
value: "https://api.x.ai/v1"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: "Qwen (DashScope Intl)",
|
|
38
|
+
value: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
label: "Qwen (DashScope CN)",
|
|
42
|
+
value: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
label: "Qwen (DashScope US)",
|
|
46
|
+
value: "https://dashscope-us.aliyuncs.com/compatible-mode/v1"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: "Perplexity",
|
|
50
|
+
value: "https://api.perplexity.ai"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
label: "Fireworks",
|
|
54
|
+
value: "https://api.fireworks.ai/inference/v1"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: "SambaNova",
|
|
58
|
+
value: "https://api.sambanova.ai/v1"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
label: "Hyperbolic",
|
|
62
|
+
value: "https://api.hyperbolic.xyz/v1"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
label: "Kimi",
|
|
66
|
+
value: "https://api.moonshot.ai/v1"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
label: "ProxyAPI",
|
|
70
|
+
value: "https://openai.api.proxyapi.ru/v1"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
label: "Custom",
|
|
74
|
+
value: AI_CUSTOM_ENDPOINT_VALUE
|
|
75
|
+
}
|
|
76
|
+
];
|
|
77
|
+
var KNOWN_AI_ENDPOINTS = new Set(
|
|
78
|
+
AI_ENDPOINT_OPTIONS.map((option) => option.value).filter(
|
|
79
|
+
(value) => value !== AI_CUSTOM_ENDPOINT_VALUE
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
var normalizeUrl = (value) => value.replace(/\/+$/, "");
|
|
83
|
+
var isIpv4Address = (value) => /^(?:\d{1,3}\.){3}\d{1,3}$/.test(value.trim());
|
|
84
|
+
var parseIpv4Address = (value) => value.trim().split(".").map((part) => Number(part));
|
|
85
|
+
var isPrivateIpv4Address = (value) => {
|
|
86
|
+
if (!isIpv4Address(value)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const [a, b, c, d] = parseIpv4Address(value);
|
|
90
|
+
if ([a, b, c, d].some(
|
|
91
|
+
(part) => !Number.isInteger(part) || part < 0 || part > 255
|
|
92
|
+
)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return a === 10 || a === 127 || a === 0 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168;
|
|
96
|
+
};
|
|
97
|
+
var isPrivateHostname = (hostname) => {
|
|
98
|
+
const normalized = hostname.trim().toLowerCase();
|
|
99
|
+
if (!normalized) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || normalized.endsWith(".internal") || normalized.endsWith(".lan") || normalized === "::1" || normalized === "[::1]" || isPrivateIpv4Address(normalized);
|
|
103
|
+
};
|
|
104
|
+
var isValidAiEndpointUrl = (value) => {
|
|
105
|
+
try {
|
|
106
|
+
const url = new URL(value);
|
|
107
|
+
return url.protocol === "https:" && !isPrivateHostname(url.hostname);
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
var normalizeAiEndpoint = (value) => {
|
|
113
|
+
if (typeof value !== "string") {
|
|
114
|
+
return "";
|
|
115
|
+
}
|
|
116
|
+
const trimmed = normalizeUrl(value.trim());
|
|
117
|
+
if (!trimmed) {
|
|
118
|
+
return "";
|
|
119
|
+
}
|
|
120
|
+
if (KNOWN_AI_ENDPOINTS.has(trimmed)) {
|
|
121
|
+
return trimmed;
|
|
122
|
+
}
|
|
123
|
+
return isValidAiEndpointUrl(trimmed) ? trimmed : "";
|
|
124
|
+
};
|
|
125
|
+
var isKnownAiEndpoint = (value) => KNOWN_AI_ENDPOINTS.has(normalizeAiEndpoint(value));
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
AI_CUSTOM_ENDPOINT_VALUE,
|
|
129
|
+
AI_ENDPOINT_OPTIONS,
|
|
130
|
+
normalizeAiEndpoint,
|
|
131
|
+
isKnownAiEndpoint
|
|
132
|
+
};
|
package/dist/ml.js
CHANGED
|
@@ -637,6 +637,44 @@ var INDICATOR_TIMEFRAMES = [
|
|
|
637
637
|
{ label: "TF4H", suffix: "4h" },
|
|
638
638
|
{ label: "TF1D", suffix: "1d" }
|
|
639
639
|
];
|
|
640
|
+
var DERIVATIVES_INTERVALS = [
|
|
641
|
+
{ label: "15M", key: "15m" },
|
|
642
|
+
{ label: "1H", key: "1h" }
|
|
643
|
+
];
|
|
644
|
+
var DERIVATIVES_PRESSURES = [
|
|
645
|
+
"neutral",
|
|
646
|
+
"crowded_long",
|
|
647
|
+
"crowded_short",
|
|
648
|
+
"long_flush",
|
|
649
|
+
"short_flush"
|
|
650
|
+
];
|
|
651
|
+
var DERIVATIVES_PRESSURE_LABELS = {
|
|
652
|
+
neutral: "Neutral",
|
|
653
|
+
crowded_long: "CrowdedLong",
|
|
654
|
+
crowded_short: "CrowdedShort",
|
|
655
|
+
long_flush: "LongFlush",
|
|
656
|
+
short_flush: "ShortFlush"
|
|
657
|
+
};
|
|
658
|
+
var DERIVATIVES_RISK_FLAGS = [
|
|
659
|
+
"missing_derivatives",
|
|
660
|
+
"stale_derivatives",
|
|
661
|
+
"crowded_long",
|
|
662
|
+
"crowded_short",
|
|
663
|
+
"oi_falling",
|
|
664
|
+
"oi_not_confirming",
|
|
665
|
+
"long_liquidation_spike",
|
|
666
|
+
"short_liquidation_spike"
|
|
667
|
+
];
|
|
668
|
+
var DERIVATIVES_RISK_FLAG_LABELS = {
|
|
669
|
+
missing_derivatives: "Missing",
|
|
670
|
+
stale_derivatives: "Stale",
|
|
671
|
+
crowded_long: "CrowdedLong",
|
|
672
|
+
crowded_short: "CrowdedShort",
|
|
673
|
+
oi_falling: "OiFalling",
|
|
674
|
+
oi_not_confirming: "OiNotConfirming",
|
|
675
|
+
long_liquidation_spike: "LongLiqSpike",
|
|
676
|
+
short_liquidation_spike: "ShortLiqSpike"
|
|
677
|
+
};
|
|
640
678
|
var toNumber = (value, fallback = 0) => {
|
|
641
679
|
if (typeof value === "number") {
|
|
642
680
|
return Number.isFinite(value) ? value : fallback;
|
|
@@ -757,6 +795,7 @@ var sliceWindow = (values, endIndex, windowSize) => {
|
|
|
757
795
|
return values.slice(start, endIndex + 1);
|
|
758
796
|
};
|
|
759
797
|
var asArray = (value) => Array.isArray(value) ? value : [];
|
|
798
|
+
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
760
799
|
var dropLastFromIndicatorSeries = (indicators) => {
|
|
761
800
|
if (!ML_WINDOW_POLICY.dropLastIndicatorElement) {
|
|
762
801
|
return indicators;
|
|
@@ -1478,6 +1517,85 @@ var buildMlTrainingRow = (signalRecord, resultRecord) => {
|
|
|
1478
1517
|
row.TrendLine_Slope = null;
|
|
1479
1518
|
}
|
|
1480
1519
|
};
|
|
1520
|
+
const applyDerivativesPhase = () => {
|
|
1521
|
+
const context2 = asRecord(signal?.additionalIndicators?.derivativesContext);
|
|
1522
|
+
const summary = asRecord(context2?.summary);
|
|
1523
|
+
const intervals = asRecord(context2?.intervals);
|
|
1524
|
+
const pressure = typeof summary?.pressure === "string" ? summary.pressure : "";
|
|
1525
|
+
const riskFlags = new Set(
|
|
1526
|
+
asArray(summary?.riskFlags).map((flag) => String(flag))
|
|
1527
|
+
);
|
|
1528
|
+
row.Deriv_HasContext = context2 ? 1 : 0;
|
|
1529
|
+
row.Deriv_Source_Coinalyze = context2?.source === "coinalyze" ? 1 : 0;
|
|
1530
|
+
row.Deriv_DirectionAligned = summary?.directionAligned === true ? 1 : summary?.directionAligned === false ? -1 : 0;
|
|
1531
|
+
for (const pressureName of DERIVATIVES_PRESSURES) {
|
|
1532
|
+
row[`Deriv_Pressure_${DERIVATIVES_PRESSURE_LABELS[pressureName]}`] = pressure === pressureName ? 1 : 0;
|
|
1533
|
+
}
|
|
1534
|
+
for (const riskFlag of DERIVATIVES_RISK_FLAGS) {
|
|
1535
|
+
row[`Deriv_Flag_${DERIVATIVES_RISK_FLAG_LABELS[riskFlag]}`] = riskFlags.has(riskFlag) ? 1 : 0;
|
|
1536
|
+
}
|
|
1537
|
+
for (const { label, key: intervalKey } of DERIVATIVES_INTERVALS) {
|
|
1538
|
+
const intervalContext = asRecord(intervals?.[intervalKey]);
|
|
1539
|
+
const prefix = `Deriv_${label}`;
|
|
1540
|
+
const asOfTs = toNumber(intervalContext?.asOfTs, entryTimestamp);
|
|
1541
|
+
const ageHours = intervalContext ? Math.max(0, safeDiv2(entryTimestamp - asOfTs, 60 * 60 * 1e3)) : 0;
|
|
1542
|
+
row[`${prefix}_Present`] = intervalContext ? 1 : 0;
|
|
1543
|
+
row[`${prefix}_Stale`] = intervalContext?.stale === true ? 1 : 0;
|
|
1544
|
+
row[`${prefix}_AgeHours_Log`] = safeLog1pPositive(ageHours);
|
|
1545
|
+
row[`${prefix}_Points_Log`] = safeLog1pPositive(
|
|
1546
|
+
toNumber(intervalContext?.points, 0)
|
|
1547
|
+
);
|
|
1548
|
+
row[`${prefix}_OpenInterest_Log`] = safeLog1pPositive(
|
|
1549
|
+
toNumber(intervalContext?.openInterest, 0)
|
|
1550
|
+
);
|
|
1551
|
+
row[`${prefix}_OiChange1h`] = clamp2(
|
|
1552
|
+
toNumber(intervalContext?.oiChangePct1h, 0) / 100,
|
|
1553
|
+
-5,
|
|
1554
|
+
5
|
|
1555
|
+
);
|
|
1556
|
+
row[`${prefix}_OiChange4h`] = clamp2(
|
|
1557
|
+
toNumber(intervalContext?.oiChangePct4h, 0) / 100,
|
|
1558
|
+
-5,
|
|
1559
|
+
5
|
|
1560
|
+
);
|
|
1561
|
+
row[`${prefix}_OiChange24h`] = clamp2(
|
|
1562
|
+
toNumber(intervalContext?.oiChangePct24h, 0) / 100,
|
|
1563
|
+
-5,
|
|
1564
|
+
5
|
|
1565
|
+
);
|
|
1566
|
+
row[`${prefix}_FundingBps`] = clamp2(
|
|
1567
|
+
toNumber(intervalContext?.fundingRate, 0) * 1e4,
|
|
1568
|
+
-100,
|
|
1569
|
+
100
|
|
1570
|
+
);
|
|
1571
|
+
row[`${prefix}_FundingZ`] = clamp2(
|
|
1572
|
+
toNumber(intervalContext?.fundingZScore, 0),
|
|
1573
|
+
-8,
|
|
1574
|
+
8
|
|
1575
|
+
);
|
|
1576
|
+
row[`${prefix}_LiqLong_Log`] = safeLog1pPositive(
|
|
1577
|
+
toNumber(intervalContext?.liqLong, 0)
|
|
1578
|
+
);
|
|
1579
|
+
row[`${prefix}_LiqShort_Log`] = safeLog1pPositive(
|
|
1580
|
+
toNumber(intervalContext?.liqShort, 0)
|
|
1581
|
+
);
|
|
1582
|
+
row[`${prefix}_LiqTotal_Log`] = safeLog1pPositive(
|
|
1583
|
+
toNumber(intervalContext?.liqTotal, 0)
|
|
1584
|
+
);
|
|
1585
|
+
row[`${prefix}_LiqImbalance`] = clamp2(
|
|
1586
|
+
toNumber(intervalContext?.liqImbalance, 0),
|
|
1587
|
+
-1,
|
|
1588
|
+
1
|
|
1589
|
+
);
|
|
1590
|
+
row[`${prefix}_LiqSpike_Log`] = safeLog1pPositive(
|
|
1591
|
+
toNumber(intervalContext?.liqSpikeRatio, 0)
|
|
1592
|
+
);
|
|
1593
|
+
row[`${prefix}_LiqSpike_Squashed`] = squash(
|
|
1594
|
+
toNumber(intervalContext?.liqSpikeRatio, 0),
|
|
1595
|
+
3
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
};
|
|
1481
1599
|
const applyLabelPhase = () => {
|
|
1482
1600
|
const profit = toNumber(resultRecord?.profit, NaN);
|
|
1483
1601
|
row.label = Number.isFinite(profit) ? profit > 0 ? 1 : 0 : null;
|
|
@@ -1487,6 +1605,7 @@ var buildMlTrainingRow = (signalRecord, resultRecord) => {
|
|
|
1487
1605
|
applyRegimePhase();
|
|
1488
1606
|
applySeriesAnalysisPhase();
|
|
1489
1607
|
applyTrendlinePhase();
|
|
1608
|
+
applyDerivativesPhase();
|
|
1490
1609
|
applyLabelPhase();
|
|
1491
1610
|
return row;
|
|
1492
1611
|
};
|
package/dist/ml.mjs
CHANGED
|
@@ -425,6 +425,44 @@ var INDICATOR_TIMEFRAMES = [
|
|
|
425
425
|
{ label: "TF4H", suffix: "4h" },
|
|
426
426
|
{ label: "TF1D", suffix: "1d" }
|
|
427
427
|
];
|
|
428
|
+
var DERIVATIVES_INTERVALS = [
|
|
429
|
+
{ label: "15M", key: "15m" },
|
|
430
|
+
{ label: "1H", key: "1h" }
|
|
431
|
+
];
|
|
432
|
+
var DERIVATIVES_PRESSURES = [
|
|
433
|
+
"neutral",
|
|
434
|
+
"crowded_long",
|
|
435
|
+
"crowded_short",
|
|
436
|
+
"long_flush",
|
|
437
|
+
"short_flush"
|
|
438
|
+
];
|
|
439
|
+
var DERIVATIVES_PRESSURE_LABELS = {
|
|
440
|
+
neutral: "Neutral",
|
|
441
|
+
crowded_long: "CrowdedLong",
|
|
442
|
+
crowded_short: "CrowdedShort",
|
|
443
|
+
long_flush: "LongFlush",
|
|
444
|
+
short_flush: "ShortFlush"
|
|
445
|
+
};
|
|
446
|
+
var DERIVATIVES_RISK_FLAGS = [
|
|
447
|
+
"missing_derivatives",
|
|
448
|
+
"stale_derivatives",
|
|
449
|
+
"crowded_long",
|
|
450
|
+
"crowded_short",
|
|
451
|
+
"oi_falling",
|
|
452
|
+
"oi_not_confirming",
|
|
453
|
+
"long_liquidation_spike",
|
|
454
|
+
"short_liquidation_spike"
|
|
455
|
+
];
|
|
456
|
+
var DERIVATIVES_RISK_FLAG_LABELS = {
|
|
457
|
+
missing_derivatives: "Missing",
|
|
458
|
+
stale_derivatives: "Stale",
|
|
459
|
+
crowded_long: "CrowdedLong",
|
|
460
|
+
crowded_short: "CrowdedShort",
|
|
461
|
+
oi_falling: "OiFalling",
|
|
462
|
+
oi_not_confirming: "OiNotConfirming",
|
|
463
|
+
long_liquidation_spike: "LongLiqSpike",
|
|
464
|
+
short_liquidation_spike: "ShortLiqSpike"
|
|
465
|
+
};
|
|
428
466
|
var toNumber = (value, fallback = 0) => {
|
|
429
467
|
if (typeof value === "number") {
|
|
430
468
|
return Number.isFinite(value) ? value : fallback;
|
|
@@ -545,6 +583,7 @@ var sliceWindow = (values, endIndex, windowSize) => {
|
|
|
545
583
|
return values.slice(start, endIndex + 1);
|
|
546
584
|
};
|
|
547
585
|
var asArray = (value) => Array.isArray(value) ? value : [];
|
|
586
|
+
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
548
587
|
var dropLastFromIndicatorSeries = (indicators) => {
|
|
549
588
|
if (!ML_WINDOW_POLICY.dropLastIndicatorElement) {
|
|
550
589
|
return indicators;
|
|
@@ -1266,6 +1305,85 @@ var buildMlTrainingRow = (signalRecord, resultRecord) => {
|
|
|
1266
1305
|
row.TrendLine_Slope = null;
|
|
1267
1306
|
}
|
|
1268
1307
|
};
|
|
1308
|
+
const applyDerivativesPhase = () => {
|
|
1309
|
+
const context2 = asRecord(signal?.additionalIndicators?.derivativesContext);
|
|
1310
|
+
const summary = asRecord(context2?.summary);
|
|
1311
|
+
const intervals = asRecord(context2?.intervals);
|
|
1312
|
+
const pressure = typeof summary?.pressure === "string" ? summary.pressure : "";
|
|
1313
|
+
const riskFlags = new Set(
|
|
1314
|
+
asArray(summary?.riskFlags).map((flag) => String(flag))
|
|
1315
|
+
);
|
|
1316
|
+
row.Deriv_HasContext = context2 ? 1 : 0;
|
|
1317
|
+
row.Deriv_Source_Coinalyze = context2?.source === "coinalyze" ? 1 : 0;
|
|
1318
|
+
row.Deriv_DirectionAligned = summary?.directionAligned === true ? 1 : summary?.directionAligned === false ? -1 : 0;
|
|
1319
|
+
for (const pressureName of DERIVATIVES_PRESSURES) {
|
|
1320
|
+
row[`Deriv_Pressure_${DERIVATIVES_PRESSURE_LABELS[pressureName]}`] = pressure === pressureName ? 1 : 0;
|
|
1321
|
+
}
|
|
1322
|
+
for (const riskFlag of DERIVATIVES_RISK_FLAGS) {
|
|
1323
|
+
row[`Deriv_Flag_${DERIVATIVES_RISK_FLAG_LABELS[riskFlag]}`] = riskFlags.has(riskFlag) ? 1 : 0;
|
|
1324
|
+
}
|
|
1325
|
+
for (const { label, key: intervalKey } of DERIVATIVES_INTERVALS) {
|
|
1326
|
+
const intervalContext = asRecord(intervals?.[intervalKey]);
|
|
1327
|
+
const prefix = `Deriv_${label}`;
|
|
1328
|
+
const asOfTs = toNumber(intervalContext?.asOfTs, entryTimestamp);
|
|
1329
|
+
const ageHours = intervalContext ? Math.max(0, safeDiv2(entryTimestamp - asOfTs, 60 * 60 * 1e3)) : 0;
|
|
1330
|
+
row[`${prefix}_Present`] = intervalContext ? 1 : 0;
|
|
1331
|
+
row[`${prefix}_Stale`] = intervalContext?.stale === true ? 1 : 0;
|
|
1332
|
+
row[`${prefix}_AgeHours_Log`] = safeLog1pPositive(ageHours);
|
|
1333
|
+
row[`${prefix}_Points_Log`] = safeLog1pPositive(
|
|
1334
|
+
toNumber(intervalContext?.points, 0)
|
|
1335
|
+
);
|
|
1336
|
+
row[`${prefix}_OpenInterest_Log`] = safeLog1pPositive(
|
|
1337
|
+
toNumber(intervalContext?.openInterest, 0)
|
|
1338
|
+
);
|
|
1339
|
+
row[`${prefix}_OiChange1h`] = clamp2(
|
|
1340
|
+
toNumber(intervalContext?.oiChangePct1h, 0) / 100,
|
|
1341
|
+
-5,
|
|
1342
|
+
5
|
|
1343
|
+
);
|
|
1344
|
+
row[`${prefix}_OiChange4h`] = clamp2(
|
|
1345
|
+
toNumber(intervalContext?.oiChangePct4h, 0) / 100,
|
|
1346
|
+
-5,
|
|
1347
|
+
5
|
|
1348
|
+
);
|
|
1349
|
+
row[`${prefix}_OiChange24h`] = clamp2(
|
|
1350
|
+
toNumber(intervalContext?.oiChangePct24h, 0) / 100,
|
|
1351
|
+
-5,
|
|
1352
|
+
5
|
|
1353
|
+
);
|
|
1354
|
+
row[`${prefix}_FundingBps`] = clamp2(
|
|
1355
|
+
toNumber(intervalContext?.fundingRate, 0) * 1e4,
|
|
1356
|
+
-100,
|
|
1357
|
+
100
|
|
1358
|
+
);
|
|
1359
|
+
row[`${prefix}_FundingZ`] = clamp2(
|
|
1360
|
+
toNumber(intervalContext?.fundingZScore, 0),
|
|
1361
|
+
-8,
|
|
1362
|
+
8
|
|
1363
|
+
);
|
|
1364
|
+
row[`${prefix}_LiqLong_Log`] = safeLog1pPositive(
|
|
1365
|
+
toNumber(intervalContext?.liqLong, 0)
|
|
1366
|
+
);
|
|
1367
|
+
row[`${prefix}_LiqShort_Log`] = safeLog1pPositive(
|
|
1368
|
+
toNumber(intervalContext?.liqShort, 0)
|
|
1369
|
+
);
|
|
1370
|
+
row[`${prefix}_LiqTotal_Log`] = safeLog1pPositive(
|
|
1371
|
+
toNumber(intervalContext?.liqTotal, 0)
|
|
1372
|
+
);
|
|
1373
|
+
row[`${prefix}_LiqImbalance`] = clamp2(
|
|
1374
|
+
toNumber(intervalContext?.liqImbalance, 0),
|
|
1375
|
+
-1,
|
|
1376
|
+
1
|
|
1377
|
+
);
|
|
1378
|
+
row[`${prefix}_LiqSpike_Log`] = safeLog1pPositive(
|
|
1379
|
+
toNumber(intervalContext?.liqSpikeRatio, 0)
|
|
1380
|
+
);
|
|
1381
|
+
row[`${prefix}_LiqSpike_Squashed`] = squash(
|
|
1382
|
+
toNumber(intervalContext?.liqSpikeRatio, 0),
|
|
1383
|
+
3
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1269
1387
|
const applyLabelPhase = () => {
|
|
1270
1388
|
const profit = toNumber(resultRecord?.profit, NaN);
|
|
1271
1389
|
row.label = Number.isFinite(profit) ? profit > 0 ? 1 : 0 : null;
|
|
@@ -1275,6 +1393,7 @@ var buildMlTrainingRow = (signalRecord, resultRecord) => {
|
|
|
1275
1393
|
applyRegimePhase();
|
|
1276
1394
|
applySeriesAnalysisPhase();
|
|
1277
1395
|
applyTrendlinePhase();
|
|
1396
|
+
applyDerivativesPhase();
|
|
1278
1397
|
applyLabelPhase();
|
|
1279
1398
|
return row;
|
|
1280
1399
|
};
|