neuroalpha 0.6.5 → 0.6.6
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.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"description": "НейроАльфа — ИИ-автопилот для рынка акций Мосбиржи: эмбеддинги акций, самообучение правил, коннекторы Т-Банк / БКС / Финам / Алор и боты Telegram / MAX",
|
|
5
5
|
"author": "Roman A. Perepelkin",
|
|
6
6
|
"license": "UNLICENSED",
|
package/server/brokers/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { barsFromHours, BAR_INTERVAL, BAR_MS } from '../model/dataset.js';
|
|
|
13
13
|
import { forecastNow } from '../model/forecast.js';
|
|
14
14
|
import { TIER1_LIQUID_SYMBOLS, symbolEdgeMult, isStockQuarantined, canEnterIntraday, shouldExitBeforeNight } from '../model/edge.js';
|
|
15
15
|
import { liveDividendGuard } from '../model/dividends.js';
|
|
16
|
-
import { STRATEGY_POLICY, sessionEdgeWarning, evaluateProfitLock, protectiveStopPct, tierSizeMult, MAX_LEVERAGE } from '../model/policy.js';
|
|
16
|
+
import { STRATEGY_POLICY, sessionEdgeWarning, evaluateProfitLock, protectiveStopPct, exitHoldRatio, tierSizeMult, MAX_LEVERAGE } from '../model/policy.js';
|
|
17
17
|
import { MODELS } from '../model/models.js';
|
|
18
18
|
import { blockingNews } from '../news/index.js';
|
|
19
19
|
import { round, MSK, DAY, fmtBarMsk } from '../util.js';
|
|
@@ -2147,10 +2147,15 @@ export async function prepareBrokerOrders(id, { onlyEntries = false, scheduledBa
|
|
|
2147
2147
|
const heldMs = effEntryTs > 0 ? Math.max(0, nowTs - effEntryTs) : 0;
|
|
2148
2148
|
const heldMin = heldMs / 60000;
|
|
2149
2149
|
const horizonMin = Math.max(90, effHorizon * 60);
|
|
2150
|
-
// Плавный переход порога удержания от мягкого (0.35 до 45 мин) к плотному (0.95 к концу горизонта 2.5 ч)
|
|
2150
|
+
// Плавный переход порога удержания от мягкого (0.35 до 45 мин) к динамическому плотному (0.95 × clamp(realizedBarPct / sigmaBarPct, 0.75, 1.25) к концу горизонта 2.5 ч)
|
|
2151
2151
|
const symMult = r.edgeMult || symbolEdgeMult(sym);
|
|
2152
|
-
const
|
|
2153
|
-
|
|
2152
|
+
const holdRatio = exitHoldRatio(heldMin, horizonMin, {
|
|
2153
|
+
sigmaBarPct: Number(r.day?.sigmaBarPct || r.sigmaPct) || 0,
|
|
2154
|
+
realizedBarPct: Number(r.day?.realizedBarPct) || 0,
|
|
2155
|
+
baseEndRatio: exitRatio,
|
|
2156
|
+
autoAdapt,
|
|
2157
|
+
});
|
|
2158
|
+
const rampedExitThr = round((fc.thresholdPct || 0) * holdRatio, 3);
|
|
2154
2159
|
const curExitThr = round(rampedExitThr * symMult, 3);
|
|
2155
2160
|
const softExitThr = round(earlyExitThresholdPct * symMult, 3);
|
|
2156
2161
|
const nightExit = !onlyEntries && autoAdapt && shouldExitBeforeNight(nowTs, effEntryTs, stepBars, BAR_INTERVAL);
|
package/server/model/policy.js
CHANGED
|
@@ -34,6 +34,10 @@ export const STRATEGY_POLICY = Object.freeze({
|
|
|
34
34
|
// паузы повторного входа после выхода, минуты
|
|
35
35
|
cooldownMin: 30,
|
|
36
36
|
stopCooldownMin: 60,
|
|
37
|
+
// динамическая подстройка верхнего порога удержания (0.95) по фактической внутридневной волатильности акции (realizedBarPct / sigmaBarPct):
|
|
38
|
+
// в спокойный день (множитель до 0.75×) не вытряхивает позицию раньше времени, в турбулентный день (до 1.25×) быстрее фиксирует выход при затухании прогноза.
|
|
39
|
+
// Проверка 09.11.2026 (06.2024–11.2026, плечо 3×): CAGR 58,6%/52,1% по половинам (весь 55,1%, PF 1,97, DD 6,4%) против 57,5%/48,1% (весь 52,6%, PF 1,89, DD 6,8%).
|
|
40
|
+
exitVolClamp: Object.freeze([0.75, 1.25]),
|
|
37
41
|
});
|
|
38
42
|
|
|
39
43
|
// ---------- окна начала и конца сессий (широкий спред, гэпы, аукционы) ----------
|
|
@@ -95,6 +99,22 @@ export function protectiveStopPct(side, { sigmaBarPct = 0, realizedBarPct = 0, h
|
|
|
95
99
|
return side === 'long' ? (st.longPct ?? 7.0) : (st.shortPct ?? 7.0);
|
|
96
100
|
}
|
|
97
101
|
|
|
102
|
+
// ---------- порог удержания (выхода по ослаблению прогноза) ----------
|
|
103
|
+
// Первые 45 минут действует мягкий порог 0.35, затем к концу горизонта (horizonMin) он плавно поднимается к baseEndRatio (0.95),
|
|
104
|
+
// масштабированному по отношению фактического сегодняшнего размаха свечей бумаги (realizedBarPct) к её обычной волатильности (sigmaBarPct) в коридоре [0.75..1.25].
|
|
105
|
+
export function exitHoldRatio(heldMin, horizonMin, { sigmaBarPct = 0, realizedBarPct = 0, baseEndRatio = 0.95, autoAdapt = true } = {}, policy = STRATEGY_POLICY) {
|
|
106
|
+
if (!autoAdapt) return baseEndRatio;
|
|
107
|
+
const startRatio = 0.35;
|
|
108
|
+
const ramp = heldMin <= 45 ? 0 : Math.min(1, (heldMin - 45) / Math.max(1, horizonMin - 45));
|
|
109
|
+
let endRatio = baseEndRatio;
|
|
110
|
+
const clamp = policy?.exitVolClamp;
|
|
111
|
+
if (Array.isArray(clamp) && clamp.length === 2 && sigmaBarPct > 0 && realizedBarPct > 0) {
|
|
112
|
+
const vr = Math.max(clamp[0], Math.min(clamp[1], realizedBarPct / sigmaBarPct));
|
|
113
|
+
endRatio = baseEndRatio * vr;
|
|
114
|
+
}
|
|
115
|
+
return startRatio + (endRatio - startRatio) * ramp;
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
// ---------- плечо и множители размера по эшелонам ----------
|
|
99
119
|
export const MAX_LEVERAGE = 7;
|
|
100
120
|
export function tierSizeMult(symbol, leverage = 1, policy = STRATEGY_POLICY) {
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
isStockQuarantined, canEnterIntraday, shouldExitBeforeNight, isMarketDown,
|
|
18
18
|
} from './edge.js';
|
|
19
19
|
import { nextDividendAt, dividendRules } from './dividends.js';
|
|
20
|
-
import { STRATEGY_POLICY, MAX_LEVERAGE, sessionEdgeWarning, profitLockLevels, protectiveStopPct, targetPositionRub, counterTrendBlocked, thesisStopPx, dayContext } from './policy.js';
|
|
20
|
+
import { STRATEGY_POLICY, MAX_LEVERAGE, sessionEdgeWarning, profitLockLevels, protectiveStopPct, exitHoldRatio, targetPositionRub, counterTrendBlocked, thesisStopPx, dayContext } from './policy.js';
|
|
21
21
|
|
|
22
22
|
// Выравнивание внешнего ряда (свечи IMOEXF, дневные цены LQDT) по шкале датасета с переносом последней цены
|
|
23
23
|
export function alignSeries(timeline, rows) {
|
|
@@ -245,8 +245,10 @@ export function simulateStrategy({ ds, wf, p, policy = STRATEGY_POLICY, capital
|
|
|
245
245
|
if (pos.side === 'long' ? fl.crash : fl.squeeze) { exitsAt.push([i, 'Защита от сквиза/обвала', 'regime']); continue; }
|
|
246
246
|
if (policy.signalExit === false) continue;
|
|
247
247
|
const heldMin = barsHeldNext * BAR_INTERVAL;
|
|
248
|
-
const
|
|
249
|
-
const
|
|
248
|
+
const sigmaBarPct = sg[i] * 100;
|
|
249
|
+
const ctx = dayContext(ds, i, t, sigmaBarPct);
|
|
250
|
+
const holdRatio = exitHoldRatio(heldMin, horizonMin, { sigmaBarPct, realizedBarPct: ctx.realizedBarPct, baseEndRatio: 0.95, autoAdapt: true }, policy);
|
|
251
|
+
const thr = holdRatio * need * mult[i] * tierScale(i);
|
|
250
252
|
const soft = 0.35 * need * mult[i] * tierScale(i);
|
|
251
253
|
const e = edge(i);
|
|
252
254
|
const signed = pos.side === 'long' ? e : -e;
|