neuroalpha 0.2.0 → 0.3.13

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 (52) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +9 -3
  3. package/bin/cli.js +69 -69
  4. package/config/seed-run.json +1 -0
  5. package/config/strategy.json +4 -10
  6. package/deploy/install.sh +128 -0
  7. package/docs//320/224/320/225/320/237/320/233/320/236/320/231.md +103 -0
  8. 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
  9. 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
  10. package/package.json +15 -5
  11. package/public/admin.html +449 -0
  12. package/public/app.js +1182 -379
  13. package/public/index.html +87 -22
  14. package/public/landing.html +1217 -870
  15. package/public/legal.html +51 -8
  16. package/public/styles.css +71 -16
  17. package/server/api/routes.js +220 -35
  18. package/server/auth/index.js +633 -340
  19. package/server/billing/yookassa.js +1 -0
  20. package/server/brokers/index.js +1369 -645
  21. package/server/config.js +6 -4
  22. package/server/data/moex.js +1 -0
  23. package/server/db.js +69 -4
  24. package/server/hub.js +1 -0
  25. package/server/index.js +10 -2
  26. package/server/llm/client.js +1 -0
  27. package/server/llm/providers.js +50 -3
  28. package/server/model/dataset.js +362 -352
  29. package/server/model/forecast.js +202 -37
  30. package/server/model/linalg.js +1 -0
  31. package/server/model/live.js +476 -486
  32. package/server/model/metrics.js +1 -0
  33. package/server/model/models.js +31 -21
  34. package/server/model/profiles.js +1 -0
  35. package/server/model/research.js +128 -205
  36. package/server/model/vocab.js +1 -0
  37. package/server/news/index.js +1 -0
  38. package/server/notify/index.js +304 -168
  39. package/server/params-meta.js +22 -26
  40. package/server/settings.js +1 -0
  41. package/server/strategist/analytics.js +2 -1
  42. package/server/strategist/index.js +7 -7
  43. package/server/strategist/tools.js +2 -1
  44. package/server/util.js +1 -0
  45. package/server/model/gpu-worker.html +0 -11
  46. package/server/model/gpu-worker.js +0 -60
  47. package/server/model/tf-node.js +0 -26
  48. package/server/model/transformer-core.js +0 -330
  49. package/server/model/transformer-gpu.js +0 -221
  50. package/server/model/transformer-pool.js +0 -200
  51. package/server/model/transformer-worker.js +0 -28
  52. package/server/model/transformer.js +0 -57
@@ -1,3 +1,4 @@
1
+ // Copyright (c) 2026 Roman A. Perepelkin. All rights reserved. Proprietary software.
1
2
  import { round } from '../util.js';
2
3
 
3
4
  const MSK = 3 * 3600000;
@@ -1,3 +1,4 @@
1
+ // Copyright (c) 2026 Roman A. Perepelkin. All rights reserved. Proprietary software.
1
2
  import { eigenSym, ridgeSolve, matrix, spearman, kmeans } from './linalg.js';
2
3
  import { BAR_INTERVAL } from './dataset.js';
3
4
 
@@ -19,11 +20,13 @@ for (const k of KINDS) for (const s of SCALES) for (const b of BETAS) HEADS.push
19
20
  // trainStart..testStart — окно обучения; testStart..testEnd — месяц прогноза.
20
21
  // Все массивы «по времени»: [u*N + i], u = t - lo.
21
22
  // textWeight (0..1) — вес «текстовой» близости по профилям бизнеса; profiles — Map(тикер → 20 чисел), загружается один раз на исследование.
22
- export function buildFold(ds, { trainStart, testStart, testEnd, H, embedDim, textWeight = 0, profiles = null }) {
23
+ export function buildFold(ds, { trainStart, testStart, testEnd, H, embedDim, textWeight = 0, profiles = null, multiHorizon = false }) {
23
24
  const { tokens, mret, T } = ds;
24
25
  const N = tokens.length;
26
+ const Hfast = Math.max(2, Math.round(H * 0.6));
27
+ const Hslow = Math.round(H * 1.4);
25
28
  const lo = Math.max(1, trainStart - FEATURE_WARMUP);
26
- const hi = Math.min(T, testEnd + H + 2);
29
+ const hi = Math.min(T, testEnd + (multiHorizon ? Hslow : H) + 2);
27
30
  const W = hi - lo;
28
31
 
29
32
  // чувствительность к рынку и обычный размах — только по окну обучения
@@ -80,20 +83,35 @@ export function buildFold(ds, { trainStart, testStart, testEnd, H, embedDim, tex
80
83
  }
81
84
  });
82
85
  // цель: остаточное (без рынка) движение, которое реально можно получить: решение на закрытии свечи t,
83
- // вход по цене открытия t+1, выход по цене открытия t+1+H
86
+ // вход по цене открытия t+1, выход по цене открытия t+1+H (в режиме multiHorizon — взвешенная траектория 0.6H / 1.0H / 1.4H)
84
87
  const { mopen } = ds;
85
88
  const yz = new Float64Array(W * N), yraw = new Float64Array(W * N), yok = new Uint8Array(W);
89
+ const invFast = 1 / Math.sqrt(Hfast), invMid = 1 / Math.sqrt(H), invSlow = 1 / Math.sqrt(Hslow);
86
90
  for (let u = 0; u + 1 + H < W; u++) {
87
91
  const t = lo + u;
88
92
  const ma = mopen[t + 1], mb = mopen[t + 1 + H];
89
93
  if (!(ma > 0 && mb > 0)) continue;
90
94
  yok[u] = 1;
91
- const m = Math.log(mb / ma);
95
+ const mMid = Math.log(mb / ma);
96
+ const hasMulti = multiHorizon && (t + 1 + Hslow < T) && mopen[t + 1 + Hfast] > 0 && mopen[t + 1 + Hslow] > 0;
97
+ const mFast = hasMulti ? Math.log(mopen[t + 1 + Hfast] / ma) : 0;
98
+ const mSlow = hasMulti ? Math.log(mopen[t + 1 + Hslow] / ma) : 0;
92
99
  for (let i = 0; i < N; i++) {
93
- const a = tokens[i].open[t + 1], b = tokens[i].open[t + 1 + H];
94
- const r = a > 0 && b > 0 ? Math.log(b / a) - beta[i] * m : 0;
95
- yraw[u * N + i] = r;
96
- yz[u * N + i] = Math.max(-8, Math.min(8, r / (sigma[i] * Math.sqrt(H))));
100
+ const opn = tokens[i].open;
101
+ const a = opn[t + 1], b = opn[t + 1 + H];
102
+ const rMid = a > 0 && b > 0 ? Math.log(b / a) - beta[i] * mMid : 0;
103
+ yraw[u * N + i] = rMid;
104
+ const sig = sigma[i];
105
+ const zMid = Math.max(-8, Math.min(8, (rMid / sig) * invMid));
106
+ if (hasMulti && a > 0 && opn[t + 1 + Hfast] > 0 && opn[t + 1 + Hslow] > 0) {
107
+ const rFast = Math.log(opn[t + 1 + Hfast] / a) - beta[i] * mFast;
108
+ const rSlow = Math.log(opn[t + 1 + Hslow] / a) - beta[i] * mSlow;
109
+ const zFast = Math.max(-8, Math.min(8, (rFast / sig) * invFast));
110
+ const zSlow = Math.max(-8, Math.min(8, (rSlow / sig) * invSlow));
111
+ yz[u * N + i] = 0.25 * zFast + 0.50 * zMid + 0.25 * zSlow;
112
+ } else {
113
+ yz[u * N + i] = zMid;
114
+ }
97
115
  }
98
116
  }
99
117
 
@@ -196,7 +214,7 @@ export function buildFold(ds, { trainStart, testStart, testEnd, H, embedDim, tex
196
214
  if (list.length) macro = { list };
197
215
  }
198
216
 
199
- return { N, lo, hi, W, trainStart, testStart, testEnd, H, beta, sigma, z, has, liq, X, yz, yraw, yok, emb, embN, cos, eigenvalues: eigVals, macro };
217
+ return { N, lo, hi, W, trainStart, testStart, testEnd, H, Hfast, Hslow, multiHorizon, beta, sigma, z, has, liq, X, yz, yraw, yok, emb, embN, cos, eigenvalues: eigVals, macro };
200
218
  }
201
219
 
202
220
  // Ликвидная акция: сделки хотя бы в 15 из последних 20 свечей
@@ -205,7 +223,8 @@ export const LIQ_MIN = 15;
205
223
  // В обучение — только моменты, цель которых целиком лежит в окне обучения (без заглядывания в месяц прогноза)
206
224
  export const trainUs = (f) => {
207
225
  const us = [];
208
- for (let t = f.trainStart + FEATURE_WARMUP; t < f.testStart - f.H - 1; t++) { const u = t - f.lo; if (f.yok[u]) us.push(u); }
226
+ const maxH = f.multiHorizon ? f.Hslow : f.H;
227
+ for (let t = f.trainStart + FEATURE_WARMUP; t < f.testStart - maxH - 1; t++) { const u = t - f.lo; if (f.yok[u]) us.push(u); }
209
228
  return us;
210
229
  };
211
230
 
@@ -386,19 +405,10 @@ export const MODELS = {
386
405
  inertia: { label: 'Своя инерция', fit: fitInertia, predict: predictInertia },
387
406
  leadlag: { label: 'Кто за кем ходит', fit: fitLeadLag, predict: (m, f, u) => predictLin(m.W, f, u) },
388
407
  attention: { label: 'Внимание через карту', fit: fitAttention, predict: predictAttention },
389
- // ступень 3: нейросеть с вниманием между акциями (tfjs грузится только при первом обучении);
390
- // fit асинхронный, после использования модель нужно освободить: model.dispose()
391
- transformer: {
392
- label: 'Трансформер',
393
- fit: async (f, opts) => (await import('./transformer.js')).fitTransformer(f, opts),
394
- predict: (m, f, u) => m.predictOne(m, f, u),
395
- predictMany: (m, f, us) => m.predictMany(m, f, us),
396
- heavy: true,
397
- },
398
408
  };
399
409
 
400
- // Какие модели обучать: три базовые всегда, трансформер — если включён для сравнения или торгует
401
- export const modelNames = (p) => Object.keys(MODELS).filter((n) => !MODELS[n].heavy || (n === 'transformer' && (p.modelUseTransformer || p.modelType === 'transformer')));
410
+ // Какие модели обучать: три базовые модели
411
+ export const modelNames = () => Object.keys(MODELS);
402
412
 
403
413
  // Объяснение прогноза «внимания»: вклад каждого соседа в прогноз акции j
404
414
  export function explainAttention(m, f, u, j, top = 3) {
@@ -1,3 +1,4 @@
1
+ // Copyright (c) 2026 Roman A. Perepelkin. All rights reserved. Proprietary software.
1
2
  import { kvGet, kvSet } from '../db.js';
2
3
  import { ensureVocab } from './vocab.js';
3
4
  import { chatStream, extractJson, isLlmEnabled } from '../llm/client.js';