neuroalpha 0.5.4 → 0.5.5
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 +1 -1
- package/server/brokers/index.js +4 -14
- package/server/model/models.js +4 -2
- package/server/model/research.js +3 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neuroalpha",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "НейроАльфа — ИИ-автопилот для рынка акций Мосбиржи: эмбеддинги акций, самообучение правил, коннекторы Т-Банк / БКС / Финам / Алор и боты Telegram / MAX",
|
|
5
5
|
"author": "Roman A. Perepelkin",
|
|
6
6
|
"license": "UNLICENSED",
|
package/server/brokers/index.js
CHANGED
|
@@ -354,7 +354,7 @@ function computeExecutionAudit(a) {
|
|
|
354
354
|
slipTier1Pct,
|
|
355
355
|
slipTier2Pct,
|
|
356
356
|
totalCostPerSidePct,
|
|
357
|
-
breakEvenTargetPct: 0.
|
|
357
|
+
breakEvenTargetPct: 0.237,
|
|
358
358
|
grossRub,
|
|
359
359
|
feesRub: round(feesRub, 0),
|
|
360
360
|
netRub,
|
|
@@ -1498,20 +1498,10 @@ export async function prepareBrokerOrders(id, { onlyEntries = false } = {}) {
|
|
|
1498
1498
|
const rawTopK = Number(params.modelTopK ?? 2);
|
|
1499
1499
|
const autoK = rawTopK === 0 || autoAdapt;
|
|
1500
1500
|
const K = rawTopK > 0 ? rawTopK : 4;
|
|
1501
|
-
|
|
1501
|
+
// Отбор до K кандидатов, прошедших абсолютный порог выгоды (единый с бэктестом в research.js)
|
|
1502
|
+
const filterBrokerDynamicTopK = (cands, _needVal, maxCount) => {
|
|
1502
1503
|
if (!cands.length || maxCount <= 0) return [];
|
|
1503
|
-
|
|
1504
|
-
if (!autoK || lim <= 1) return cands.slice(0, lim);
|
|
1505
|
-
const bestE = Math.abs(cands[0].expectedPct || 0);
|
|
1506
|
-
const out = [cands[0]];
|
|
1507
|
-
for (let m = 1; m < lim; m++) {
|
|
1508
|
-
const curE = Math.abs(cands[m].expectedPct || 0);
|
|
1509
|
-
const relMin = m === 1 ? 0.62 : 0.78;
|
|
1510
|
-
const absMin = m === 1 ? needVal * 1.15 : needVal * 1.45;
|
|
1511
|
-
if (curE >= bestE * relMin && curE >= absMin) out.push(cands[m]);
|
|
1512
|
-
else break;
|
|
1513
|
-
}
|
|
1514
|
-
return out;
|
|
1504
|
+
return cands.slice(0, Math.min(cands.length, maxCount));
|
|
1515
1505
|
};
|
|
1516
1506
|
// Автоматическая подстройка направления и мощности торговли под тариф и реальные данные счёта:
|
|
1517
1507
|
const marginAllowed = acc.lastSync?.marginEnabled !== false;
|
package/server/model/models.js
CHANGED
|
@@ -480,11 +480,13 @@ function predictAttention(m, f, u) {
|
|
|
480
480
|
s += ML[mi].b[i] * zz;
|
|
481
481
|
}
|
|
482
482
|
// Равный ансамбль 50/50 с базовой моделью своей инерции (при наличии весов inertiaCoef):
|
|
483
|
-
//
|
|
483
|
+
// если внимание к соседям и собственная инерция смотрят в разные стороны (s * sIn < 0),
|
|
484
|
+
// ослабляем сигнал вдвое, чтобы не проходить порог входа на конфликте моделей, но не искажать ранговый порядок IC!
|
|
484
485
|
if (m.inertiaCoef) {
|
|
485
486
|
let sIn = 0;
|
|
486
487
|
for (let q = 0; q < 3; q++) sIn += m.inertiaCoef[q] * f.X[0][q][k];
|
|
487
|
-
|
|
488
|
+
const mix = 0.50 * s + 0.50 * sIn;
|
|
489
|
+
s = s * sIn >= 0 ? mix : mix * 0.5;
|
|
488
490
|
}
|
|
489
491
|
out[i] = s;
|
|
490
492
|
}
|
package/server/model/research.js
CHANGED
|
@@ -279,24 +279,10 @@ async function run(runId, p, state) {
|
|
|
279
279
|
const rawTopK = Number(p.modelTopK ?? 2);
|
|
280
280
|
const autoK = rawTopK === 0 || autoAdapt;
|
|
281
281
|
const K = rawTopK > 0 ? rawTopK : 4;
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
// достаточно силён относительно лидера (>= 68% от силы №1) и уверенно перекрывает порог (>= 1.25 * need),
|
|
285
|
-
// чтобы не размывать капитал на слабые окраинные сигналы
|
|
286
|
-
const filterDynamicTopK = (cands, edgeFn, needVal, maxCount) => {
|
|
282
|
+
// Отбор до K кандидатов, прошедших абсолютный порог выгоды (без отсева 2..K из-за сравнения с лидером №1 — проверено на IS и OOS)
|
|
283
|
+
const filterDynamicTopK = (cands, _edgeFn, _needVal, maxCount) => {
|
|
287
284
|
if (!cands.length || maxCount <= 0) return [];
|
|
288
|
-
|
|
289
|
-
if (!autoK || lim <= 1) return cands.slice(0, lim);
|
|
290
|
-
const bestE = Math.abs(edgeFn(cands[0]));
|
|
291
|
-
const out = [cands[0]];
|
|
292
|
-
for (let m = 1; m < lim; m++) {
|
|
293
|
-
const curE = Math.abs(edgeFn(cands[m]));
|
|
294
|
-
const relMin = m === 1 ? 0.62 : 0.78;
|
|
295
|
-
const absMin = m === 1 ? needVal * 1.15 : needVal * 1.45;
|
|
296
|
-
if (curE >= bestE * relMin && curE >= absMin) out.push(cands[m]);
|
|
297
|
-
else break;
|
|
298
|
-
}
|
|
299
|
-
return out;
|
|
285
|
+
return cands.slice(0, Math.min(cands.length, maxCount));
|
|
300
286
|
};
|
|
301
287
|
const dir = p.modelDirection;
|
|
302
288
|
const exitRatio = Number(p.modelExitRatio ?? 0.5);
|