neuroalpha 0.5.19 → 0.5.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neuroalpha",
3
- "version": "0.5.19",
3
+ "version": "0.5.20",
4
4
  "description": "НейроАльфа — ИИ-автопилот для рынка акций Мосбиржи: эмбеддинги акций, самообучение правил, коннекторы Т-Банк / БКС / Финам / Алор и боты Telegram / MAX",
5
5
  "author": "Roman A. Perepelkin",
6
6
  "license": "UNLICENSED",
package/public/admin.html CHANGED
@@ -20,6 +20,7 @@
20
20
  --yellow: #eab308;
21
21
  }
22
22
  * { box-sizing: border-box; }
23
+ [hidden] { display: none !important; }
23
24
  body { margin: 0; background: var(--bg); color: var(--text); font: 14px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }
24
25
  a, a:visited { color: var(--accent); text-decoration: none; }
25
26
  a.brand, a.brand:visited { color: var(--text); }
@@ -197,7 +198,7 @@
197
198
  <section data-pane="oauth" hidden>
198
199
  <div class="card">
199
200
  <h2>Провайдеры быстрого входа (OAuth 2.0)</h2>
200
- <p class="sub">Настройка кнопок входа в 1 клик на витрине <code>/landing</code>. Скопируйте Callback URL в настройки соответствующего провайдера.</p>
201
+ <p class="sub">Настройка кнопок входа в 1 клик на витрине <code>/landing</code>. Иностранные провайдеры (Google) автоматически скрываются для пользователей из российского сегмента в соответствии с ФЗ № 406-ФЗ / 149-ФЗ. Скопируйте Callback URL в настройки соответствующего провайдера.</p>
201
202
  <form id="form-oauth" class="grid-form">
202
203
  <div id="oauth-rows" class="grid-form"></div>
203
204
  <div><button type="submit" class="primary">Сохранить OAuth-провайдеров</button></div>
package/public/app.js CHANGED
@@ -1089,10 +1089,11 @@ async function loadForecast(force, silent = false) {
1089
1089
  const thrVal = isShort
1090
1090
  ? (r.shortThresholdPct ?? (isT1 ? shortThr : shortThrT2))
1091
1091
  : (r.buyThresholdPct ?? (isT1 ? buyThr : buyThrT2));
1092
- const thrText = isShort ? `−${fmtNum(thrVal, 2)}%` : fmtPct(thrVal, 2);
1093
- const tierDesc = isT1
1094
- ? '1-й эшелон ликвидности (узкий спред стакана): базовый порог'
1095
- : '2–3-й эшелон (широкий спред стакана): порог повышен в 1,20× для покрытия реального проскальзывания';
1092
+ const thrFmt = Number(thrVal || 0).toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
1093
+ const thrText = isShort ? `−${thrFmt}%` : `+${thrFmt}%`;
1094
+ const multStr = r.edgeMult ? `×${fmtNum(r.edgeMult, 2)}` : (isT1 ? '×1,00' : '×1,20');
1095
+ const sigStr = r.sigmaPct ? `, волатильность 10-мин свечи σ = ${fmtNum(r.sigmaPct, 2)}%` : '';
1096
+ const tierDesc = `${isT1 ? '1-й эшелон' : '2–3-й эшелон'}, индивидуальный множитель ${multStr}${sigStr}`;
1096
1097
  const thrTitle = isShort
1097
1098
  ? `Индивидуальный порог шорта для ${r.symbol}: ниже −${fmtNum(thrVal, 2)}% (${tierDesc})`
1098
1099
  : `Индивидуальный порог покупки для ${r.symbol}: выше ${fmtPct(thrVal, 2)} (${tierDesc})`;
@@ -1116,7 +1117,7 @@ async function loadForecast(force, silent = false) {
1116
1117
  const fcTable = (title, rows, extraStyle = '', side = 'long') => `<table class="fc-table" style="table-layout:fixed;width:100%${extraStyle}">${colgroup}<thead><tr><th>${title}</th><th class="num">Цена</th><th class="num">Ожидание</th><th class="num">Динамика</th><th style="text-align:center">Сигнал</th><th>Под влиянием</th><th class="num" title="Индивидуальный порог входа с учётом ликвидности бумаги (1-й или 2–3-й эшелон) и тренда индекса">Порог</th></tr></thead><tbody>${rows.map((r) => row(r, side)).join('')}</tbody></table>`;
1117
1118
  box.innerHTML = `<div style="overflow-x:auto">${fcTable('Сильнее рынка', shownRows.slice(0, 6), '', 'long')}
1118
1119
  ${fcTable('Слабее рынка', shortRows, ';margin-top:14px', 'short')}</div>
1119
- <p class="muted small">Ожидание — движение относительно рынка в целом (авто-пересчёт каждые 15 сек по живым ценам Мосбиржи). Индивидуальный порог каждой акции указан в колонке <b>«Порог»</b> (1-й эшелон / 2–3-й эшелон со спредом шире): «Купить» — ожидание выше <b>${fmtPct(buyThr, 2)} / ${fmtPct(buyThrT2, 2)}</b>.${f.direction && f.direction !== 'long' ? ` «Шорт» — ожидание ниже <b>−${fmtNum(shortThr, 2)}% / −${fmtNum(shortThrT2, 2)}%</b> (с учётом тренда индекса и доступности шорта у брокера).` : ''} <span style="color:var(--blocked-fg)">Розовым</span> отмечены строки, по которым вход запрещён (запрет шорта у брокера, отсечка дивидендов, фильтр новостей или экстремальная свеча ±4,5%).</p>`;
1120
+ <p class="muted small">Ожидание — движение относительно рынка в целом (авто-пересчёт каждые 15 сек по живым ценам Мосбиржи). Точный индивидуальный порог каждой акции рассчитывается в колонке <b>«Порог»</b> с учётом её ликвидности (оборота торгов), волатильности свечи и тренда индекса. <span style="color:var(--blocked-fg)">Розовым</span> отмечены строки, по которым вход запрещён (запрет шорта у брокера, отсечка дивидендов, фильтр новостей или экстремальная свеча ±4,5%).</p>`;
1120
1121
  if (state.brokers?.accounts?.length) renderBrokers();
1121
1122
  } catch (e) {
1122
1123
  if (!silent) box.innerHTML = `<span class="neg">Не получилось: ${esc(e.message)}</span>`;
@@ -3703,10 +3704,10 @@ async function renderCloudPane() {
3703
3704
  Брокерских счетов: до <b>${u.limits?.maxBrokerAccounts ?? 0}</b> (${capLimStr}) · Режим торговли: <b>${dirLimStr}</b>${u.planUntil ? ` · Оплачен до ${fmtDate(u.planUntil)}` : ''}.
3704
3705
  </div>
3705
3706
  </div>
3706
- ${me.cloudMode ? `<div class="row-gap" style="flex-wrap:wrap">
3707
- <button type="button" id="btn-cloud-verify">Проверить оплату</button>
3708
- <button type="button" id="btn-cloud-logout">Выйти</button>
3709
- </div>` : ''}
3707
+ <div class="row-gap" style="flex-wrap:wrap">
3708
+ ${me.cloudMode ? `<button type="button" id="btn-cloud-verify">Проверить оплату</button>` : ''}
3709
+ ${(me.cloudMode || me.role === 'instance' || !isDefaultLocal) ? `<button type="button" id="btn-cloud-logout">Выйти</button>` : ''}
3710
+ </div>
3710
3711
  </div>
3711
3712
  <div class="srow sblock">
3712
3713
  <div class="stxt">