neuroalpha 0.2.0 → 0.3.12
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/LICENSE +21 -0
- package/README.md +7 -3
- package/bin/cli.js +69 -69
- package/config/seed-run.json +1 -0
- package/config/strategy.json +4 -10
- package/deploy/install.sh +128 -0
- package/docs//320/224/320/225/320/237/320/233/320/236/320/231.md +103 -0
- package/docs//320/230/320/235/320/241/320/242/320/240/320/243/320/232/320/246/320/230/320/257.md +1 -1
- package/docs//320/234/320/225/320/245/320/220/320/235/320/230/320/232/320/220_/320/230_/320/237/320/220/320/240/320/220/320/234/320/225/320/242/320/240/320/253.md +171 -0
- package/package.json +15 -5
- package/public/admin.html +426 -0
- package/public/app.js +741 -251
- package/public/index.html +45 -20
- package/public/landing.html +1004 -870
- package/public/legal.html +22 -0
- package/public/styles.css +49 -15
- package/server/api/routes.js +176 -23
- package/server/auth/index.js +544 -340
- package/server/billing/yookassa.js +1 -0
- package/server/brokers/index.js +1224 -645
- package/server/config.js +6 -4
- package/server/data/moex.js +1 -0
- package/server/db.js +53 -2
- package/server/hub.js +1 -0
- package/server/index.js +10 -2
- package/server/llm/client.js +1 -0
- package/server/llm/providers.js +50 -3
- package/server/model/dataset.js +362 -352
- package/server/model/forecast.js +15 -21
- package/server/model/linalg.js +1 -0
- package/server/model/live.js +489 -486
- package/server/model/metrics.js +1 -0
- package/server/model/models.js +31 -21
- package/server/model/profiles.js +1 -0
- package/server/model/research.js +119 -172
- package/server/model/vocab.js +1 -0
- package/server/news/index.js +1 -0
- package/server/notify/index.js +304 -168
- package/server/params-meta.js +20 -25
- package/server/settings.js +1 -0
- package/server/strategist/analytics.js +1 -0
- package/server/strategist/index.js +6 -6
- package/server/strategist/tools.js +2 -1
- package/server/util.js +1 -0
- package/server/model/gpu-worker.html +0 -11
- package/server/model/gpu-worker.js +0 -60
- package/server/model/tf-node.js +0 -26
- package/server/model/transformer-core.js +0 -330
- package/server/model/transformer-gpu.js +0 -221
- package/server/model/transformer-pool.js +0 -200
- package/server/model/transformer-worker.js +0 -28
- package/server/model/transformer.js +0 -57
package/server/model/forecast.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roman A. Perepelkin. Licensed under the MIT License.
|
|
1
2
|
import { normalizeParams } from '../settings.js';
|
|
2
3
|
import { round, DAY, fmtBarMsk } from '../util.js';
|
|
3
4
|
import { loadDataset, barsFromHours, BAR_MS, BAR_INTERVAL } from './dataset.js';
|
|
@@ -18,37 +19,28 @@ export const lastClosedIndex = (ds, now = Date.now()) => {
|
|
|
18
19
|
// Обучение на окне, заканчивающемся свечой idx, и прогноз по этой свече.
|
|
19
20
|
// Возвращает строки по всем акциям: ожидаемое движение (относительно рынка), сигнал покупки, кто влияет.
|
|
20
21
|
export async function predictAt(ds, p, idx, { explain = true } = {}) {
|
|
21
|
-
const
|
|
22
|
+
const autoAdapt = p.modelAutoAdapt !== false;
|
|
23
|
+
const effHorizon = autoAdapt ? 2.5 : p.modelHorizon;
|
|
24
|
+
const effMinEdge = autoAdapt ? 2.5 : p.modelMinEdge;
|
|
25
|
+
const H = barsFromHours(effHorizon);
|
|
26
|
+
const maxH = autoAdapt ? Math.round(H * 1.4) : H;
|
|
22
27
|
const trainLen = Math.round(p.modelTrainDays * ds.barsPerDay);
|
|
23
|
-
const trainStart = Math.max(FEATURE_WARMUP +
|
|
28
|
+
const trainStart = Math.max(FEATURE_WARMUP + maxH + 2, idx - trainLen);
|
|
24
29
|
// «текстовая» часть карты: устойчивые описания бизнеса (профили готовятся отдельно, здесь только читаем)
|
|
25
30
|
const profiles = p.modelTextWeight > 0 ? loadProfiles() : null;
|
|
26
|
-
const f = buildFold(ds, { trainStart, testStart: idx, testEnd: idx + 1, H, embedDim: p.modelEmbedDim, textWeight: p.modelTextWeight, profiles });
|
|
31
|
+
const f = buildFold(ds, { trainStart, testStart: idx, testEnd: idx + 1, H, embedDim: p.modelEmbedDim, textWeight: p.modelTextWeight, profiles, multiHorizon: autoAdapt });
|
|
27
32
|
const u = idx - f.lo;
|
|
28
33
|
const chosen = p.modelType in MODELS ? p.modelType : 'attention';
|
|
29
|
-
const
|
|
30
|
-
// трансформер обучается здесь, только если торгует он (для сравнения — только в исследовании)
|
|
31
|
-
const list = [...new Set(explain ? [...Object.keys(MODELS).filter((n) => !MODELS[n].heavy), chosen] : need)];
|
|
34
|
+
const list = [...new Set(explain ? Object.keys(MODELS) : ['attention', chosen])];
|
|
32
35
|
const fitted = {};
|
|
33
36
|
const preds = {};
|
|
34
37
|
for (const n of list) {
|
|
35
|
-
if (n === 'transformer') {
|
|
36
|
-
// ~минута обучения — в отдельном потоке (или на видеокарте), чтобы сервер не замирал
|
|
37
|
-
const tm = await import('./transformer.js');
|
|
38
|
-
const { fitPredictIsolated } = await import('./transformer-pool.js');
|
|
39
|
-
const r = await fitPredictIsolated(tm.transformerInput(f), [u], tm.transformerCfg(p), { gpu: p.transformerGpu });
|
|
40
|
-
fitted[n] = { name: n, info: r.info, where: r.where };
|
|
41
|
-
preds[n] = r.preds.get(u);
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
38
|
fitted[n] = await MODELS[n].fit(f);
|
|
45
39
|
preds[n] = MODELS[n].predict(fitted[n], f, u);
|
|
46
|
-
if (fitted[n].dispose) fitted[n].dispose();
|
|
47
40
|
}
|
|
48
41
|
const cost = (p.commissionPct + p.slippagePct) / 100;
|
|
49
|
-
const threshold =
|
|
42
|
+
const threshold = effMinEdge * 2 * cost;
|
|
50
43
|
const bear = isMarketDown(ds, idx);
|
|
51
|
-
const autoAdapt = p.modelAutoAdapt !== false;
|
|
52
44
|
const dir = p.modelDirection || 'long';
|
|
53
45
|
const needL = autoAdapt && bear && dir !== 'neutral' ? threshold * 1.25 : threshold;
|
|
54
46
|
const needS = autoAdapt && dir === 'longshort' ? (bear ? threshold * 0.90 : threshold * 1.25) : threshold;
|
|
@@ -94,7 +86,10 @@ function withNews(result, p) {
|
|
|
94
86
|
// Прогноз на ближайшие H часов по последней закрытой свече
|
|
95
87
|
export async function forecastNow(input, { force = false, onProgress } = {}) {
|
|
96
88
|
const p = normalizeParams(input);
|
|
97
|
-
const
|
|
89
|
+
const autoAdapt = p.modelAutoAdapt !== false;
|
|
90
|
+
const effHorizon = autoAdapt ? 2.5 : p.modelHorizon;
|
|
91
|
+
const effMinEdge = autoAdapt ? 2.5 : p.modelMinEdge;
|
|
92
|
+
const key = JSON.stringify([autoAdapt, p.modelType, effHorizon, p.modelTrainDays, p.modelEmbedDim, effMinEdge, p.modelDirection, p.modelUseMacro, p.modelUseDividends, p.modelTextWeight, p.commissionPct, p.slippagePct]);
|
|
98
93
|
if (!force && cache && cache.key === key && Date.now() - cache.at < 10 * 60000) return withNews(cache.result, p);
|
|
99
94
|
if (!force && inflight.has(key)) return withNews(await inflight.get(key), p);
|
|
100
95
|
const task = (async () => {
|
|
@@ -107,11 +102,10 @@ export async function forecastNow(input, { force = false, onProgress } = {}) {
|
|
|
107
102
|
at: now,
|
|
108
103
|
barTs: ds.timeline[last],
|
|
109
104
|
bar: fmtBarMsk(ds.timeline[last]),
|
|
110
|
-
horizon:
|
|
105
|
+
horizon: effHorizon, direction: p.modelDirection, model: r.chosen, thresholdPct: round(r.threshold * 100, 3), marketDown: r.marketDown,
|
|
111
106
|
rows: r.rows.map(({ i, expected, ...x }) => ({ ...x, cluster: snap.clusters[i] })).sort((a, b) => b.expectedPct - a.expectedPct),
|
|
112
107
|
map: { symbols: ds.tokens.map((t) => t.symbol), names: ds.tokens.map((t) => t.name), pts: snap.pts.map(([x, y]) => [round(x, 3), round(y, 3)]), cl: snap.clusters },
|
|
113
108
|
heads: HEADS.map((h, i) => ({ label: h.label, coef: round(r.fitted.attention.coef[i], 4) })),
|
|
114
|
-
...(r.fitted.transformer ? { transformer: { device: r.fitted.transformer.where, bestEpoch: r.fitted.transformer.info.bestEpoch, epochs: r.fitted.transformer.info.epochs } } : {}),
|
|
115
109
|
};
|
|
116
110
|
cache = { key, at: now, result };
|
|
117
111
|
return result;
|
package/server/model/linalg.js
CHANGED