@tradejs/node 1.0.6 → 1.0.8

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/dist/ai.js CHANGED
@@ -46,6 +46,7 @@ __export(ai_exports, {
46
46
  trimSeriesDeep: () => trimSeriesDeep
47
47
  });
48
48
  module.exports = __toCommonJS(ai_exports);
49
+ var import_aiLanguages = require("@tradejs/infra/aiLanguages");
49
50
  var import_redis = require("@tradejs/infra/redis");
50
51
  var import_userSettings = require("@tradejs/infra/userSettings");
51
52
 
@@ -73,6 +74,109 @@ var trimSeriesDeep = (value) => {
73
74
  return value;
74
75
  };
75
76
 
77
+ // src/aiMarketContext.ts
78
+ var SESSION_WINDOWS = [
79
+ { name: "asia", startMinuteUtc: 0, endMinuteUtc: 8 * 60 },
80
+ { name: "europe", startMinuteUtc: 7 * 60, endMinuteUtc: 16 * 60 },
81
+ { name: "us", startMinuteUtc: 13 * 60, endMinuteUtc: 22 * 60 }
82
+ ];
83
+ var toRecord = (value) => {
84
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
85
+ return null;
86
+ }
87
+ return value;
88
+ };
89
+ var toFiniteNumber = (value) => {
90
+ const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
91
+ return Number.isFinite(numeric) ? numeric : null;
92
+ };
93
+ var getLastFiniteNumber = (value) => {
94
+ const numeric = toFiniteNumber(value);
95
+ if (numeric != null) {
96
+ return numeric;
97
+ }
98
+ if (!Array.isArray(value)) {
99
+ return null;
100
+ }
101
+ for (let i = value.length - 1; i >= 0; i -= 1) {
102
+ const nested = getLastFiniteNumber(value[i]);
103
+ if (nested != null) {
104
+ return nested;
105
+ }
106
+ }
107
+ return null;
108
+ };
109
+ var roundTo = (value, decimals) => {
110
+ const factor = 10 ** decimals;
111
+ return Math.round(value * factor) / factor;
112
+ };
113
+ var isInsideSession = (minuteUtc, startMinuteUtc, endMinuteUtc) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
114
+ var buildTradingSessionContext = (timestamp) => {
115
+ const date = new Date(timestamp);
116
+ const utcHour = date.getUTCHours();
117
+ const utcMinute = date.getUTCMinutes();
118
+ const minuteUtc = utcHour * 60 + utcMinute;
119
+ const activeSessions = SESSION_WINDOWS.filter(
120
+ (session) => isInsideSession(minuteUtc, session.startMinuteUtc, session.endMinuteUtc)
121
+ ).map((session) => session.name);
122
+ const primarySession = activeSessions.includes("us") ? "us" : activeSessions.includes("europe") ? "europe" : activeSessions.includes("asia") ? "asia" : "off_hours";
123
+ return {
124
+ timezone: "UTC",
125
+ utcHour,
126
+ utcMinute,
127
+ primarySession,
128
+ activeSessions,
129
+ isOverlap: activeSessions.length > 1,
130
+ overlap: activeSessions.length > 1 ? `${activeSessions.join("_")}_overlap` : null
131
+ };
132
+ };
133
+ var buildMissingSpreadContext = () => ({
134
+ source: "binance_coinbase_btc",
135
+ indicatorKey: "payload.indicators.spread",
136
+ available: false,
137
+ value: null,
138
+ bps: null,
139
+ absBps: null,
140
+ bias: null,
141
+ severity: null
142
+ });
143
+ var buildSpreadContextFromValue = (spread) => {
144
+ const value = roundTo(spread, 8);
145
+ const bps = roundTo(value * 1e4, 2);
146
+ const absBps = Math.abs(bps);
147
+ const bias = Math.abs(bps) < 1 ? "flat" : bps > 0 ? "coinbase_premium" : "binance_premium";
148
+ const severity = absBps >= 20 ? "wide" : absBps >= 5 ? "elevated" : "normal";
149
+ return {
150
+ source: "binance_coinbase_btc",
151
+ indicatorKey: "payload.indicators.spread",
152
+ available: true,
153
+ value,
154
+ bps,
155
+ absBps,
156
+ bias,
157
+ severity
158
+ };
159
+ };
160
+ var readSpreadFromSignal = (signal) => {
161
+ const indicatorSpread = getLastFiniteNumber(signal.indicators?.spread);
162
+ if (indicatorSpread != null) {
163
+ return indicatorSpread;
164
+ }
165
+ return getLastFiniteNumber(signal.additionalIndicators?.spread);
166
+ };
167
+ var buildAiMarketContext = (signal) => {
168
+ const existingMarketContext = toRecord(
169
+ signal.additionalIndicators?.marketContext
170
+ );
171
+ const existingSpread = toRecord(existingMarketContext?.binanceCoinbaseSpread);
172
+ const spread = readSpreadFromSignal(signal);
173
+ return {
174
+ ...existingMarketContext ?? {},
175
+ tradingSession: buildTradingSessionContext(signal.timestamp),
176
+ binanceCoinbaseSpread: spread != null ? buildSpreadContextFromValue(spread) : existingSpread ?? buildMissingSpreadContext()
177
+ };
178
+ };
179
+
76
180
  // src/strategy/manifests.ts
77
181
  var import_indicators = require("@tradejs/core/indicators");
78
182
  var import_logger2 = require("@tradejs/infra/logger");
@@ -82,6 +186,7 @@ var import_fs = __toESM(require("fs"));
82
186
  var import_path = __toESM(require("path"));
83
187
  var import_module = require("module");
84
188
  var import_url = require("url");
189
+ var import_config = require("@tradejs/core/config");
85
190
  var import_logger = require("@tradejs/infra/logger");
86
191
  var CONFIG_FILE_NAMES = [
87
192
  "tradejs.config.ts",
@@ -114,10 +219,14 @@ var normalizeConfig = (rawConfig) => {
114
219
  const strategies2 = Array.isArray(config.strategies) ? config.strategies.map((value) => String(value || "").trim()).filter(Boolean) : [];
115
220
  const indicators = Array.isArray(config.indicators) ? config.indicators.map((value) => String(value || "").trim()).filter(Boolean) : [];
116
221
  const connectors = Array.isArray(config.connectors) ? config.connectors.map((value) => String(value || "").trim()).filter(Boolean) : [];
222
+ const hooks = (0, import_config.normalizeTradejsConfigHooks)(
223
+ config.hooks
224
+ );
117
225
  return {
118
226
  strategies: strategies2,
119
227
  indicators,
120
- connectors
228
+ connectors,
229
+ ...hooks ? { hooks } : {}
121
230
  };
122
231
  };
123
232
  var getRequireFn = (cwd = getTradejsProjectCwd()) => (0, import_module.createRequire)(import_path.default.join(import_path.default.resolve(cwd), "__tradejs_loader__.js"));
@@ -487,24 +596,36 @@ var strategies = new Proxy(
487
596
  );
488
597
 
489
598
  // src/strategyAdapters/ai.ts
490
- var buildBaseAiPayload = (signal) => ({
491
- signal: {
492
- symbol: signal.symbol,
493
- signalId: signal.signalId,
494
- interval: signal.interval,
495
- direction: signal.direction,
496
- timestamp: signal.timestamp,
497
- strategy: signal.strategy,
498
- prices: {
499
- currentPrice: signal.prices.currentPrice,
500
- takeProfitPrice: signal.prices.takeProfitPrice,
501
- stopLossPrice: signal.prices.stopLossPrice
502
- }
503
- },
504
- figures: trimSeriesDeep(signal.figures ?? {}),
505
- indicators: trimSeriesDeep(signal.indicators),
506
- additionalIndicators: trimSeriesDeep(signal.additionalIndicators ?? {})
507
- });
599
+ var toRecord2 = (value) => {
600
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
601
+ return {};
602
+ }
603
+ return value;
604
+ };
605
+ var buildBaseAiPayload = (signal) => {
606
+ const additionalIndicators = {
607
+ ...toRecord2(signal.additionalIndicators),
608
+ marketContext: buildAiMarketContext(signal)
609
+ };
610
+ return {
611
+ signal: {
612
+ symbol: signal.symbol,
613
+ signalId: signal.signalId,
614
+ interval: signal.interval,
615
+ direction: signal.direction,
616
+ timestamp: signal.timestamp,
617
+ strategy: signal.strategy,
618
+ prices: {
619
+ currentPrice: signal.prices.currentPrice,
620
+ takeProfitPrice: signal.prices.takeProfitPrice,
621
+ stopLossPrice: signal.prices.stopLossPrice
622
+ }
623
+ },
624
+ figures: trimSeriesDeep(signal.figures ?? {}),
625
+ indicators: trimSeriesDeep(signal.indicators),
626
+ additionalIndicators: trimSeriesDeep(additionalIndicators)
627
+ };
628
+ };
508
629
  var defaultAiAdapter = {};
509
630
  var getStrategyAiAdapter = (strategy) => getStrategyManifest(strategy)?.aiAdapter ?? defaultAiAdapter;
510
631
  var getSignalAiAdapter = (signal) => getStrategyAiAdapter(signal.strategy);
@@ -532,8 +653,8 @@ var parseAIResponse = (input) => {
532
653
  if (!match) throw new Error("JSON block not found");
533
654
  return JSON.parse(match[0]);
534
655
  } catch (err) {
535
- console.error("\u274C \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0430\u0440\u0441\u0438\u043D\u0433\u0430 AI-\u043E\u0442\u0432\u0435\u0442\u0430:", err);
536
- console.log("\u{1F50D} \u0418\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442:", input);
656
+ console.error("Failed to parse AI response:", err);
657
+ console.log("Raw AI response:", input);
537
658
  return {};
538
659
  }
539
660
  };
@@ -597,22 +718,22 @@ var getDeterministicQuality = (gateContext) => {
597
718
  return Array.isArray(gateContext?.structuralHardBlockReasons) && gateContext.structuralHardBlockReasons.length > 0 ? 2 : 3;
598
719
  };
599
720
  var buildAiSystemPrompt = (signal) => `
600
- \u0422\u044B \u2014 \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0438\u0439 \u043A\u043B\u0430\u0441\u0441\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B \u0440\u044B\u043D\u043A\u0430 \u0434\u043B\u044F \u0443\u0436\u0435 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043D\u043D\u043E\u0433\u043E \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u0433\u043E \u0441\u0438\u0433\u043D\u0430\u043B\u0430.
601
- \u0410\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u0443\u0439 \u043F\u0440\u0438\u0441\u043B\u0430\u043D\u043D\u044B\u0439 JSON \u0441\u043E \u0441\u0434\u0435\u043B\u043A\u043E\u0439, \u0441\u0432\u0435\u0447\u0430\u043C\u0438, \u0438\u043D\u0434\u0438\u043A\u0430\u0442\u043E\u0440\u0430\u043C\u0438 (\u043F\u043E \u043C\u043E\u043D\u0435\u0442\u0435 \u0438 BTC \u043D\u0430 \u0440\u0430\u0437\u043D\u044B\u0445 \u0422\u0424) \u0438 \u0444\u0438\u0433\u0443\u0440\u0430\u043C\u0438/\u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438.
602
- \u0414\u0430\u043D\u043D\u044B\u0435 \u0440\u044F\u0434\u043E\u0432 \u0443\u0436\u0435 \u0443\u043A\u043E\u0440\u043E\u0447\u0435\u043D\u044B \u0434\u043E \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0445 5 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439.
721
+ You are an internal market-structure classifier for an already computed system signal.
722
+ Analyze the provided JSON containing the trade, candles, indicators (for the coin and BTC across multiple timeframes), and strategy figures/context.
723
+ Series data is already trimmed to the latest 5 values.
603
724
 
604
- \u0412\u0410\u0416\u041D\u041E:
605
- - \u041D\u0435 \u043F\u0440\u0438\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u0434\u0430\u043D\u043D\u044B\u0435.
606
- - \u042D\u0442\u043E \u0437\u0430\u0434\u0430\u0447\u0430 \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0435\u0433\u043E \u0430\u0443\u0434\u0438\u0442\u0430/\u043A\u043B\u0430\u0441\u0441\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438, \u0430 \u043D\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u0430\u044F \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u044F \u043A \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044E.
607
- - \u041D\u0435 \u0444\u043E\u0440\u043C\u0438\u0440\u0443\u0439 \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u0438 \u043F\u043E \u0438\u0441\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044E, \u043D\u0435 \u043C\u0435\u043D\u044F\u0439 \u0438\u0441\u0445\u043E\u0434\u043D\u0443\u044E \u0433\u0438\u043F\u043E\u0442\u0435\u0437\u0443 \u043D\u0430 \u043D\u043E\u0432\u0443\u044E \u0438 \u043D\u0435 \u0434\u0430\u0432\u0430\u0439 \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0445 \u0438\u043D\u0432\u0435\u0441\u0442\u0438\u0446\u0438\u043E\u043D\u043D\u044B\u0445 \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u0439.
608
- - \u041E\u043F\u0438\u0440\u0430\u0439\u0441\u044F \u043D\u0430 \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0438 \u0443\u0440\u043E\u0432\u043D\u0438 \u0438\u0441\u0445\u043E\u0434\u043D\u043E\u0433\u043E \u0441\u0438\u0433\u043D\u0430\u043B\u0430, \u043D\u043E \u043C\u043E\u0436\u0435\u0448\u044C \u0443\u043A\u0430\u0437\u0430\u0442\u044C, \u0447\u0442\u043E \u0442\u0435\u043A\u0443\u0449\u0430\u044F \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u0441 \u043D\u0438\u043C\u0438 \u043D\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u0443\u0435\u0442\u0441\u044F.
609
- - \u0423\u0447\u0438\u0442\u044B\u0432\u0430\u0439, \u0447\u0442\u043E \u0441\u0438\u0433\u043D\u0430\u043B \u043F\u043E\u0441\u0442\u0440\u043E\u0435\u043D \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0435\u0439, \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u043E\u0439 \u0432 \u043F\u043E\u043B\u0435 signal.strategy.
610
- - \u0422\u0432\u043E\u044F \u0446\u0435\u043B\u044C: \u043E\u043F\u0438\u0441\u0430\u0442\u044C, \u043D\u0430\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u0435\u043C\u0430\u044F \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u0441\u043E\u0433\u043B\u0430\u0441\u0443\u0435\u0442\u0441\u044F \u0441 \u0443\u0436\u0435 \u0441\u0444\u043E\u0440\u043C\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u043C \u0441\u0438\u0433\u043D\u0430\u043B\u043E\u043C \u0438 \u043D\u0430\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u0438\u0433\u043D\u0430\u043B \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u043E \u0441\u0435\u0439\u0447\u0430\u0441.
611
- - \u041D\u0435 \u043F\u0438\u0448\u0438 \u0430\u0431\u0441\u0442\u0440\u0430\u043A\u0442\u043D\u043E \u0432\u0440\u043E\u0434\u0435 "\u0435\u0441\u0442\u044C momentum/slope" \u0431\u0435\u0437 \u043F\u0440\u0438\u0432\u044F\u0437\u043A\u0438 \u043A \u0440\u0435\u0448\u0435\u043D\u0438\u044E.
612
- - \u041F\u0438\u0448\u0438 comment \u043F\u043E-\u0440\u0443\u0441\u0441\u043A\u0438.
613
- - \u0415\u0441\u043B\u0438 \u0443\u0432\u0435\u0440\u0435\u043D\u043D\u043E\u0441\u0442\u044C \u043D\u0435\u043F\u043E\u043B\u043D\u0430\u044F, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u043E\u0441\u0442\u043E\u0440\u043E\u0436\u043D\u044B\u0435 \u0444\u043E\u0440\u043C\u0443\u043B\u0438\u0440\u043E\u0432\u043A\u0438 ("\u0441\u043A\u043E\u0440\u0435\u0435", "\u043F\u043E\u043A\u0430 \u043D\u0435\u0442 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F", "\u0432\u0435\u0440\u043E\u044F\u0442\u043D\u043E"), \u0430 \u043D\u0435 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u0447\u043D\u044B\u0435 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F.
725
+ Important:
726
+ - Do not invent missing data.
727
+ - This is an internal audit/classification task, not user-facing trading advice.
728
+ - Do not generate execution instructions, do not replace the original thesis with a new one, and do not provide personalized investment advice.
729
+ - Use the original signal direction and levels as the anchor, but you may state that the current structure does not support them.
730
+ - Respect the source strategy specified in \`signal.strategy\`.
731
+ - Your goal is to explain how well the observed structure matches the existing signal and how structurally confirmed it is right now.
732
+ - Do not write vague statements like "there is momentum/slope" without tying them to the decision.
733
+ - Write all user-visible text fields in the requested response language. If no explicit language instruction is provided later, default to English.
734
+ - If confidence is incomplete, prefer cautious wording such as "likely", "not confirmed yet", or "probably" instead of categorical claims.
614
735
 
615
- \u041E\u0442\u0432\u0435\u0447\u0430\u0439 \u0441\u0442\u0440\u043E\u0433\u043E \u041E\u0414\u041D\u0418\u041C JSON-\u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \u0431\u0435\u0437 \u0442\u0435\u043A\u0441\u0442\u0430 \u0432\u043E\u043A\u0440\u0443\u0433:
736
+ Return exactly one JSON object and nothing else:
616
737
 
617
738
  {
618
739
  "direction": payload.signal.direction | null,
@@ -630,95 +751,106 @@ var buildAiSystemPrompt = (signal) => `
630
751
  "triggerInvalidation": string
631
752
  }
632
753
 
633
- - \u041D\u0435 \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u0439 \u0434\u0440\u0443\u0433\u0438\u0435 \u043F\u043E\u043B\u044F.
634
- - \u0412\u0441\u0435 \u0447\u0438\u0441\u043B\u0430 \u0434\u043E\u043B\u0436\u043D\u044B \u0431\u044B\u0442\u044C \u043A\u043E\u043D\u0435\u0447\u043D\u044B\u043C\u0438 (finite), \u0431\u0435\u0437 NaN/Infinity.
635
- - \u0412\u0441\u0435 \u0442\u0435\u043A\u0441\u0442\u043E\u0432\u044B\u0435 \u043F\u043E\u043B\u044F \u2014 \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0435 \u0441\u0442\u0440\u043E\u043A\u0438 (\u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u043D\u043E\u0441\u043E\u0432, \u0431\u0435\u0437 markdown-\u0441\u043F\u0438\u0441\u043A\u043E\u0432).
636
- - "direction" \u2014 \u043D\u0435 \u043D\u043E\u0432\u0430\u044F \u0442\u043E\u0440\u0433\u043E\u0432\u0430\u044F \u0438\u0434\u0435\u044F, \u0430 \u0442\u043E\u043B\u044C\u043A\u043E \u0444\u043B\u0430\u0433 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u043E\u0441\u0442\u0438 \u0441 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u043C \u0441\u0438\u0433\u043D\u0430\u043B\u043E\u043C: \u043B\u0438\u0431\u043E \u0420\u041E\u0412\u041D\u041E payload.signal.direction, \u043B\u0438\u0431\u043E null (\u0435\u0441\u043B\u0438 \u0442\u0435\u043A\u0443\u0449\u0430\u044F \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442 \u044D\u0442\u043E\u0442 \u0441\u0438\u0433\u043D\u0430\u043B). \u041D\u0438\u043A\u043E\u0433\u0434\u0430 \u043D\u0435 \u043F\u0440\u0435\u0434\u043B\u0430\u0433\u0430\u0439 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u043F\u043E\u043B\u043E\u0436\u043D\u043E\u0435 \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435.
637
- - "quality" \u2014 \u0443\u0440\u043E\u0432\u0435\u043D\u044C \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u043E\u0433\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u0441\u0438\u0433\u043D\u0430\u043B\u0430 \u0418\u041C\u0415\u041D\u041D\u041E \u0421\u0415\u0419\u0427\u0410\u0421 (timing + \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F), \u0430 \u043D\u0435 \u043E\u0431\u0449\u0430\u044F \u043F\u0440\u0438\u0432\u043B\u0435\u043A\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u0438\u0434\u0435\u0438 \u0438 \u043D\u0435 \u0438\u043D\u0432\u0435\u0441\u0442\u0438\u0446\u0438\u043E\u043D\u043D\u044B\u0439 \u0441\u043E\u0432\u0435\u0442.
638
- - "needRetest" \u2014 \u043D\u0443\u0436\u0435\u043D \u043B\u0438 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 confirmation \u043F\u043E \u0443\u0440\u043E\u0432\u043D\u044E, \u0447\u0442\u043E\u0431\u044B \u0441\u0447\u0438\u0442\u0430\u0442\u044C \u0442\u0435\u043A\u0443\u0449\u0438\u0439 \u0441\u0438\u0433\u043D\u0430\u043B \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u044B\u043C.
639
- - "retestPrice" \u2014 \u043A\u043B\u044E\u0447\u0435\u0432\u043E\u0439 \u0443\u0440\u043E\u0432\u0435\u043D\u044C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F/\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B (\u0438\u043B\u0438 null, \u0435\u0441\u043B\u0438 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0443\u0440\u043E\u0432\u0435\u043D\u044C \u043D\u0435 \u043D\u0443\u0436\u0435\u043D / \u043D\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0451\u043D).
640
- - "takeProfitPrice" \u0438 "stopLossPrice" \u2014 \u043D\u0435 \u043F\u0440\u0438\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u043D\u043E\u0432\u044B\u0435 \u0442\u043E\u0440\u0433\u043E\u0432\u044B\u0435 \u0443\u0440\u043E\u0432\u043D\u0438. \u0415\u0441\u043B\u0438 \u0443\u0436\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u043D\u044B\u0435 \u0432 payload.signal.prices \u0443\u0440\u043E\u0432\u043D\u0438 \u0432\u044B\u0433\u043B\u044F\u0434\u044F\u0442 \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u043C\u0438 \u0441 \u0442\u0435\u043A\u0443\u0449\u0435\u0439 \u0446\u0435\u043D\u043E\u0439 \u0438 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u044B\u043C \u0441\u0438\u0433\u043D\u0430\u043B\u043E\u043C, \u043C\u043E\u0436\u0435\u0448\u044C \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0438\u0445 \u043A\u0430\u043A audit existing levels; \u0438\u043D\u0430\u0447\u0435 \u0432\u0435\u0440\u043D\u0438 null.
641
- - \u0420\u0430\u0437\u0431\u0438\u0432\u0430\u0439 \u0430\u043D\u0430\u043B\u0438\u0437 \u043D\u0430 \u043F\u043E\u043B\u044F:
642
- - "setup" \u2014 \u0447\u0442\u043E \u0437\u0430 \u0441\u0435\u0442\u0430\u043F \u043F\u043E \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0435/\u0442\u0440\u0435\u043D\u0434\u043E\u0432\u043E\u0439 \u043B\u0438\u043D\u0438\u0438 \u0441\u0435\u0439\u0447\u0430\u0441.
643
- - "confirmations" \u2014 2-4 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F/\u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0430 \u043F\u043E \u0438\u043D\u0434\u0438\u043A\u0430\u0442\u043E\u0440\u0430\u043C \u043C\u043E\u043D\u0435\u0442\u044B.
644
- - "btcContext" \u2014 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043B\u0438 BTC \u0438\u0434\u0435\u044E \u0438\u043B\u0438 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u0435\u0442.
645
- - "retestPlan" \u2014 \u0447\u0442\u043E \u0434\u043E\u043B\u0436\u043D\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0443 \u043D\u0430 \u043A\u043B\u044E\u0447\u0435\u0432\u043E\u043C \u0443\u0440\u043E\u0432\u043D\u0435 (\u0438\u043B\u0438 \u043F\u043E\u0447\u0435\u043C\u0443 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0443\u0440\u043E\u0432\u0435\u043D\u044C \u043D\u0435 \u043D\u0443\u0436\u0435\u043D).
646
- - "riskLevels" \u2014 \u043A\u0440\u0430\u0442\u043A\u043E \u043F\u0440\u043E \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u043E\u0441\u0442\u044C \u0443\u0436\u0435 \u0437\u0430\u0434\u0430\u043D\u043D\u044B\u0445 \u0443\u0440\u043E\u0432\u043D\u0435\u0439/\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B \u0440\u0438\u0441\u043A\u0430, \u0431\u0435\u0437 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u043E\u0432\u043E\u0433\u043E \u043F\u043B\u0430\u043D\u0430 \u0441\u0434\u0435\u043B\u043A\u0438.
647
- - "qualityReason" \u2014 \u043F\u043E\u0447\u0435\u043C\u0443 quality \u0438\u043C\u0435\u043D\u043D\u043E \u0442\u0430\u043A\u043E\u0439.
648
- - "triggerInvalidation" \u2014 \u0447\u0442\u043E \u0434\u043E\u043B\u0436\u043D\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u0441\u0438\u0433\u043D\u0430\u043B / \u0447\u0442\u043E \u043E\u0442\u043C\u0435\u043D\u044F\u0435\u0442 \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u0435\u043C\u0443\u044E \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u0443\u044E \u0433\u0438\u043F\u043E\u0442\u0435\u0437\u0443.
649
- - "comment" \u043D\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D. \u0415\u0441\u043B\u0438 \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0448\u044C, \u043D\u0435 \u0434\u0443\u0431\u043B\u0438\u0440\u0443\u0439 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u044B\u0435 \u043F\u043E\u043B\u044F.
754
+ - Do not add any other fields.
755
+ - All numbers must be finite, with no \`NaN\` or \`Infinity\`.
756
+ - All text fields must be short strings with no line breaks and no markdown lists.
757
+ - \`direction\` is not a new trade idea. It is only a compatibility flag for the existing signal: either exactly \`payload.signal.direction\` or \`null\` if the current structure does not confirm that signal. Never propose the opposite direction.
758
+ - \`quality\` is the structural confirmation level of the current signal right now, including timing and confirmations. It is not a general attractiveness score and not investment advice.
759
+ - \`needRetest\` indicates whether an additional confirmation level is required before the current signal can be treated as structurally confirmed.
760
+ - \`retestPrice\` is the key level that would confirm or invalidate the structure, or \`null\` if no extra level is needed or available.
761
+ - \`takeProfitPrice\` and \`stopLossPrice\` must not be newly invented levels. If the levels already supplied in \`payload.signal.prices\` still look internally coherent relative to the current price and the confirmed signal, you may return them as an audit of existing levels; otherwise return \`null\`.
762
+ - Use these fields as separate parts of the analysis:
763
+ - \`setup\`: the current structural setup or trendline state.
764
+ - \`confirmations\`: 2-4 concrete confirmations or conflicts from the coin indicators.
765
+ - \`btcContext\`: whether BTC supports the idea, is neutral, or conflicts with it.
766
+ - \`retestPlan\`: what must happen at the key level to confirm the structure, or why no extra level is needed.
767
+ - \`riskLevels\`: a short note on whether the existing levels and risk structure are internally coherent, without creating a new trade plan.
768
+ - \`qualityReason\`: why the quality score is what it is.
769
+ - \`triggerInvalidation\`: what must happen to confirm the signal or what invalidates the current structural thesis.
770
+ - \`comment\` is optional. If you include it, do not just duplicate the structured fields.
650
771
 
651
- \u0415\u0441\u043B\u0438 \u0434\u0430\u043D\u043D\u044B\u0445 \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u0442\u043E\u0447\u043D\u043E \u0438\u043B\u0438 \u0441\u0435\u0442\u0430\u043F \u0441\u043B\u0430\u0431\u044B\u0439 \u2014 \u0432\u0435\u0440\u043D\u0438 "direction": null, quality <= 2 \u0438 \u043E\u0431\u044A\u044F\u0441\u043D\u0438 \u043F\u043E\u0447\u0435\u043C\u0443.
772
+ If the data is insufficient or the setup is weak, return \`"direction": null\`, \`quality <= 2\`, and explain why.
652
773
 
653
- \u0421\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u0432\u0445\u043E\u0434\u043D\u043E\u0433\u043E payload (JSON \u0432 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F):
774
+ Input payload structure:
654
775
  - payload.signal:
655
776
  symbol, signalId, interval, direction, timestamp, strategy, prices
656
777
  - payload.signal.prices:
657
778
  currentPrice, takeProfitPrice, stopLossPrice
658
779
  - payload.figures:
659
- \u0441\u043B\u043E\u0432\u0430\u0440\u044C strategy-specific \u0444\u0438\u0433\u0443\u0440/\u0433\u0435\u043E\u043C\u0435\u0442\u0440\u0438\u0438 (\u0435\u0441\u043B\u0438 \u0435\u0441\u0442\u044C). \u041A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u043F\u043E\u043B\u044F \u0437\u0430\u0432\u0438\u0441\u044F\u0442 \u043E\u0442 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438.
780
+ strategy-specific figures or geometry when available. Fields vary by strategy.
660
781
  - payload.indicators:
661
- \u0441\u043B\u043E\u0432\u0430\u0440\u044C \u0438\u043D\u0434\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432/\u0440\u044F\u0434\u043E\u0432 \u043F\u043E \u043C\u043E\u043D\u0435\u0442\u0435 \u0438 BTC; \u0440\u044F\u0434\u044B \u0443\u0436\u0435 \u043E\u0431\u0440\u0435\u0437\u0430\u043D\u044B \u0434\u043E \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0445 5 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439.
782
+ indicator dictionaries and series for the coin and BTC; all series are already trimmed to the latest 5 values.
662
783
  - payload.additionalIndicators:
663
- strategy-specific summary/context fields. \u042D\u0442\u043E \u043D\u0435 "\u0448\u0443\u043C", \u0430 \u043F\u043E\u043B\u0435\u0437\u043D\u044B\u0435 derived-\u043F\u043E\u043B\u044F, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044F \u043F\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u044C\u043D\u043E \u0434\u043B\u044F \u0440\u0435\u0448\u0435\u043D\u0438\u044F.
664
- \u041F\u0440\u0438\u043C\u0435\u0440\u044B: helperFlags, structureContext, spread, correlation, volatilitySummary.
665
- \u0415\u0441\u043B\u0438 \u0442\u0430\u043A\u0438\u0435 \u043F\u043E\u043B\u044F \u0435\u0441\u0442\u044C, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u0438\u0445 \u043A\u0430\u043A \u0431\u043E\u043B\u0435\u0435 \u044F\u0432\u043D\u0443\u044E \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0443, \u0447\u0435\u043C \u043F\u043E\u043F\u044B\u0442\u043A\u0443 \u0437\u0430\u043D\u043E\u0432\u043E \u0432\u044B\u0432\u0435\u0441\u0442\u0438 \u0442\u043E \u0436\u0435 \u0441\u0430\u043C\u043E\u0435 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E lines/points.
666
- \u041F\u0430\u0442\u0442\u0435\u0440\u043D\u044B \u043A\u043B\u044E\u0447\u0435\u0439:
667
- \u2022 \u043C\u043E\u043D\u0435\u0442\u0430: maFast, atrPct, macd..., candles15m/candles1h/candles4h/candles1d, \u0430 \u0442\u0430\u043A\u0436\u0435 *1h/*4h/*1d
668
- \u2022 BTC: btcMaFast, btcAtr, btcMacd..., btcCandles*, \u0430 \u0442\u0430\u043A\u0436\u0435 btc*1h/*4h/*1d
669
- \u2022 \u0441\u043B\u0443\u0436\u0435\u0431\u043D\u044B\u0435 \u043A\u043B\u044E\u0447\u0438 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u044B (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 correlation, spread, touches, distance)
784
+ strategy-specific summary/context fields. This is not noise; it contains derived fields deliberately passed by the strategy to help the decision.
785
+ Examples: helperFlags, structureContext, spread, correlation, volatilitySummary.
786
+ Always inspect \`payload.additionalIndicators.marketContext\` when present:
787
+ \u2022 \`marketContext.tradingSession\`: UTC session at signal time: asia / europe / us / overlap / off_hours.
788
+ \u2022 \`marketContext.binanceCoinbaseSpread\`: BTC spread between Coinbase and Binance from \`payload.indicators.spread\`; \`value=(Coinbase-Binance)/Binance\`, \`bps=value*10000\`.
789
+ If those fields exist, use them as a more explicit hint instead of trying to re-derive the same idea from raw lines or points.
790
+ If \`derivativesContext\` exists, it is a derived Coinalyze summary for the time of the signal. Coinalyze context is built only from \`BTCUSDT\` and \`ETHUSDT\` reference symbols, not for every target coin. \`targetSymbol\` is just the source signal coin. Use BTC/ETH open interest, funding, liquidations, and pressure/riskFlags as positioning context, not as an independent trade idea.
791
+ Key patterns:
792
+ \u2022 coin: \`maFast\`, \`atrPct\`, \`macd...\`, \`candles15m/candles1h/candles4h/candles1d\`, and \`*1h/*4h/*1d\`
793
+ \u2022 BTC: \`btcMaFast\`, \`btcAtr\`, \`btcMacd...\`, \`btcCandles*\`, and \`btc*1h/*4h/*1d\`
794
+ \u2022 strategy service keys are possible as well, for example \`correlation\`, \`spread\`, \`touches\`, \`distance\`
670
795
 
671
- \u041A\u0430\u043A \u0430\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C (\u043F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\u0442\u044B):
672
- 1) \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u044C \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0443 \u0446\u0435\u043D\u044B \u0438 \u0433\u0435\u043E\u043C\u0435\u0442\u0440\u0438\u044E/\u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u0441\u0435\u0442\u0430\u043F\u0430 \u0438\u0437 payload.figures. \u042D\u0442\u043E \u043F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\u0442\u043D\u0435\u0435 \u0438\u043D\u0434\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432.
673
- 2) \u0417\u0430\u0442\u0435\u043C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 payload.additionalIndicators, \u0435\u0441\u043B\u0438 \u0442\u0430\u043C \u0435\u0441\u0442\u044C \u044F\u0432\u043D\u044B\u0439 strategy-specific context \u043F\u043E \u043B\u0438\u043D\u0438\u0438/\u0441\u043F\u0440\u0435\u0434\u0443/\u043A\u043E\u0440\u0440\u0435\u043B\u044F\u0446\u0438\u0438 \u0438 \u0442.\u043F.
674
- 3) \u0417\u0430\u0442\u0435\u043C \u043E\u0446\u0435\u043D\u0438 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435/\u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442 \u043F\u043E \u0438\u043D\u0434\u0438\u043A\u0430\u0442\u043E\u0440\u0430\u043C \u0442\u0435\u043A\u0443\u0449\u0435\u0439 \u043C\u043E\u043D\u0435\u0442\u044B.
675
- 4) \u0417\u0430\u0442\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u044C \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 BTC (\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0438\u043B\u0438 \u043B\u043E\u043C\u0430\u0435\u0442 \u0438\u0434\u0435\u044E).
676
- 5) \u0422\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \u044D\u0442\u043E\u0433\u043E \u0432\u044B\u0431\u0435\u0440\u0438 direction, quality \u0438 \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u043F\u043E \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u043C\u0443 \u0443\u0440\u043E\u0432\u043D\u044E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F.
677
- 6) \u0415\u0441\u043B\u0438 \u0435\u0441\u0442\u044C \u0441\u0438\u043B\u044C\u043D\u044B\u0435 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u044B, \u0441\u043D\u0438\u0436\u0430\u0439 quality \u0438\u043B\u0438 \u0441\u0442\u0430\u0432\u044C null.
796
+ How to analyze, in order:
797
+ 1. Start with price structure and the setup geometry or context in \`payload.figures\`. This has higher priority than indicators.
798
+ 2. Then use \`payload.additionalIndicators\` when it contains explicit strategy-specific context such as line state, spread, correlation, and similar fields.
799
+ 3. Then assess confirmation or conflict from the current coin indicators.
800
+ 4. Then evaluate BTC context.
801
+ 5. Only after that choose \`direction\`, \`quality\`, and whether an extra confirmation level is required.
802
+ 6. If strong conflicts exist, reduce quality or set direction to \`null\`.
678
803
 
679
- \u042F\u0432\u043D\u044B\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430 \u043F\u0440\u0438 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0435 \u0441\u0438\u0433\u043D\u0430\u043B\u043E\u0432:
680
- - \u0415\u0441\u043B\u0438 \u0444\u0438\u0433\u0443\u0440\u0430/\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u0446\u0435\u043D\u044B \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u044B \u0438\u043B\u0438 \u0441\u043E\u043C\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B, \u0438\u043D\u0434\u0438\u043A\u0430\u0442\u043E\u0440\u044B \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u044B "\u0441\u043F\u0430\u0441\u0430\u0442\u044C" \u0441\u0435\u0442\u0430\u043F.
681
- - \u0415\u0441\u043B\u0438 strategy-specific helper fields \u043F\u0440\u044F\u043C\u043E \u0433\u043E\u0432\u043E\u0440\u044F\u0442, \u0447\u0442\u043E \u0441\u0438\u0433\u043D\u0430\u043B \u0435\u0449\u0435 \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D / \u0431\u0435\u0437 \u0437\u0430\u043F\u0430\u0441\u0430 / \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F, \u043D\u0435 \u0437\u0430\u0432\u044B\u0448\u0430\u0439 quality.
682
- - \u0415\u0441\u043B\u0438 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u043E\u043A, \u043D\u043E BTC \u0438/\u0438\u043B\u0438 \u043A\u043B\u044E\u0447\u0435\u0432\u044B\u0435 \u0438\u043D\u0434\u0438\u043A\u0430\u0442\u043E\u0440\u044B \u0437\u0430\u043C\u0435\u0442\u043D\u043E \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u044E\u0442, \u043E\u0431\u044B\u0447\u043D\u043E quality <= 3.
683
- - \u0415\u0441\u043B\u0438 \u0442\u0435\u043A\u0443\u0449\u0438\u0439 \u0441\u0438\u0433\u043D\u0430\u043B \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D (direction=null), \u0432 comment \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u043A\u0440\u0430\u0442\u043A\u043E \u043D\u0430\u0437\u043E\u0432\u0438 \u0433\u043B\u0430\u0432\u043D\u0443\u044E \u043F\u0440\u0438\u0447\u0438\u043D\u0443.
684
- \u0415\u0441\u043B\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0448\u044C \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u044B\u0435 \u043F\u043E\u043B\u044F, \u0443\u043A\u0430\u0436\u0438 \u0433\u043B\u0430\u0432\u043D\u0443\u044E \u043F\u0440\u0438\u0447\u0438\u043D\u0443 \u0432 "qualityReason" \u0438/\u0438\u043B\u0438 "triggerInvalidation".
804
+ Explicit conflict rules:
805
+ - If the figure or price structure is invalid or doubtful, indicators must not rescue the setup.
806
+ - If strategy-specific helper fields explicitly say the signal is not confirmed yet, lacks margin, or requires waiting, do not overstate quality.
807
+ - If the structure is acceptable but BTC or key indicators noticeably conflict, quality is usually \`<= 3\`.
808
+ - If \`derivativesContext.referenceContexts\` exists, check \`primaryReferenceSymbol\` first, then compare \`BTCUSDT\` and \`ETHUSDT\` as broad-market derivatives context. Do not search for Coinalyze data for \`targetSymbol\` unless \`targetSymbol\` itself is \`BTCUSDT\` or \`ETHUSDT\`.
809
+ - If \`derivativesContext.summary.riskFlags\` contains \`crowded_long\` for a LONG or \`crowded_short\` for a SHORT, treat that as crowded positioning and do not overstate quality without strong structural confirmation.
810
+ - If \`derivativesContext.summary.directionAligned=false\`, explicitly mention the derivatives conflict in \`confirmations\` or \`qualityReason\`.
811
+ - If \`derivativesContext\` is absent, stale, or \`missing_derivatives\`, do not infer Coinalyze conclusions and do not penalize the signal just because that data is missing.
812
+ - If \`marketContext.tradingSession\` exists, treat the session as a liquidity and volatility regime: asia is often thinner, europe/us are more active, and overlaps can amplify both momentum and noise. Do not reject a signal solely because of session, but mention clear session support or conflict in \`confirmations\` or \`qualityReason\`.
813
+ - If \`marketContext.binanceCoinbaseSpread.available=true\` and \`severity=elevated/wide\`, treat it as cross-exchange divergence or BTC liquidity risk. Do not use the spread as a standalone long/short signal, but reduce confidence or require more confirmation when the rest of the structure is weak or BTC context conflicts.
814
+ - If \`marketContext.binanceCoinbaseSpread\` is missing or \`available=false\`, do not infer anything from Binance/Coinbase spread and do not penalize the signal just because it is absent.
815
+ - If the current signal is not confirmed (\`direction=null\`), name the main reason briefly in \`comment\`.
816
+ If you use the structured fields, include the main reason in \`qualityReason\` or \`triggerInvalidation\`.
685
817
 
686
- \u041F\u0440\u0430\u0432\u0438\u043B\u0430 \u0434\u043B\u044F direction / TP / SL:
687
- - direction = LONG \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u0434\u0430\u043D\u043D\u044B\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044E\u0442 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0439 LONG-\u0441\u0438\u0433\u043D\u0430\u043B; SHORT \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044E\u0442 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0439 SHORT-\u0441\u0438\u0433\u043D\u0430\u043B; \u0438\u043D\u0430\u0447\u0435 null.
688
- - \u0414\u043B\u044F LONG \u043E\u0431\u044B\u0447\u043D\u043E stopLossPrice < currentPrice < takeProfitPrice.
689
- - \u0414\u043B\u044F SHORT \u043E\u0431\u044B\u0447\u043D\u043E takeProfitPrice < currentPrice < stopLossPrice.
690
- - \u041D\u0435 \u043E\u043F\u0442\u0438\u043C\u0438\u0437\u0438\u0440\u0443\u0439 \u0438 \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044B\u0432\u0430\u0439 TP/SL \u043F\u043E\u0434 "\u043B\u0443\u0447\u0448\u0443\u044E \u0441\u0434\u0435\u043B\u043A\u0443"; \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0446\u0435\u043D\u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u043E\u0441\u0442\u044C \u0443\u0436\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u043D\u044B\u0445 \u0443\u0440\u043E\u0432\u043D\u0435\u0439.
691
- - \u0415\u0441\u043B\u0438 direction = null, \u0442\u043E takeProfitPrice = null \u0438 stopLossPrice = null.
692
- - \u0415\u0441\u043B\u0438 needRetest = false, \u0442\u043E retestPrice = null.
693
- - \u0415\u0441\u043B\u0438 needRetest = true, retestPrice \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0443\u043A\u0430\u0437\u0430\u043D (finite number) \u0438 \u0441\u0432\u044F\u0437\u0430\u043D \u0441 \u0443\u0440\u043E\u0432\u043D\u0435\u043C \u0440\u0435\u0442\u0435\u0441\u0442\u0430/\u043F\u0440\u043E\u0431\u043E\u044F.
694
- - Sanity-check \u043F\u0435\u0440\u0435\u0434 \u043E\u0442\u0432\u0435\u0442\u043E\u043C: \u043F\u0440\u043E\u0432\u0435\u0440\u044C \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u043E\u0441\u0442\u044C direction \u0441 TP/SL \u0438 \u0442\u0435\u043A\u0443\u0449\u0435\u0439 \u0446\u0435\u043D\u043E\u0439.
818
+ Rules for \`direction\` / TP / SL:
819
+ - \`direction = LONG\` only if the data confirms the existing LONG signal; \`SHORT\` only if the data confirms the existing SHORT signal; otherwise \`null\`.
820
+ - For LONG, the expected relation is usually \`stopLossPrice < currentPrice < takeProfitPrice\`.
821
+ - For SHORT, the expected relation is usually \`takeProfitPrice < currentPrice < stopLossPrice\`.
822
+ - Do not optimize or recalculate TP/SL for a "better trade"; only assess whether the already supplied levels are coherent.
823
+ - If \`direction = null\`, then \`takeProfitPrice = null\` and \`stopLossPrice = null\`.
824
+ - If \`needRetest = false\`, then \`retestPrice = null\`.
825
+ - If \`needRetest = true\`, \`retestPrice\` must be a finite number tied to a meaningful retest or breakout level.
826
+ - Before responding, sanity-check the consistency of \`direction\`, TP/SL, and the current price.
695
827
 
696
- \u0428\u043A\u0430\u043B\u0430 quality (\u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u0432\u0441\u044E \u0448\u043A\u0430\u043B\u0443, \u043D\u0435 \u0437\u0430\u0432\u044B\u0448\u0430\u0439):
697
- - 1: \u043F\u043B\u043E\u0445\u043E\u0439/\u0445\u0430\u043E\u0442\u0438\u0447\u043D\u044B\u0439 \u0441\u0435\u0442\u0430\u043F, \u0441\u0438\u043B\u044C\u043D\u044B\u0435 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u044B, \u0441\u0438\u0433\u043D\u0430\u043B \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u043E \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D
698
- - 2: \u0441\u043B\u0430\u0431\u044B\u0439 \u0441\u0435\u0442\u0430\u043F, \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0439 \u043C\u0430\u043B\u043E, \u0441\u0438\u0433\u043D\u0430\u043B \u043F\u043E\u043A\u0430 \u0441\u043A\u043E\u0440\u0435\u0435 watch/reject
699
- - 3: \u0441\u0440\u0435\u0434\u043D\u0438\u0439 \u0441\u0435\u0442\u0430\u043F, \u0447\u0430\u0441\u0442\u044C \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B \u0435\u0441\u0442\u044C, \u043D\u043E \u043E\u0441\u0442\u0430\u044E\u0442\u0441\u044F \u0437\u0430\u043C\u0435\u0442\u043D\u044B\u0435 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u044B
700
- - 4: \u0445\u043E\u0440\u043E\u0448\u0438\u0439 \u0441\u0435\u0442\u0430\u043F, \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0439, \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u0432 \u0446\u0435\u043B\u043E\u043C \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0430
701
- - 5: \u043E\u0447\u0435\u043D\u044C \u0441\u0438\u043B\u044C\u043D\u044B\u0439 \u0441\u0435\u0442\u0430\u043F, \u0447\u0438\u0441\u0442\u0430\u044F \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 + \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F + \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044F\u044F \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u043E\u0441\u0442\u044C \u0443\u0440\u043E\u0432\u043D\u0435\u0439
828
+ Quality scale:
829
+ - 1: poor or chaotic setup, strong conflicts, signal not structurally confirmed
830
+ - 2: weak setup, few confirmations, more of a watch or reject
831
+ - 3: average setup, some structure exists, but notable conflicts remain
832
+ - 4: good setup, several confirmations, structure is mostly coherent
833
+ - 5: very strong setup, clean structure, confirmations, and internally coherent levels
702
834
 
703
- \u0422\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u043A \u043F\u043E\u043B\u0435\u0437\u043D\u043E\u043C\u0443 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E\u043C\u0443 \u0430\u043D\u0430\u043B\u0438\u0437\u0443 (\u0431\u0435\u0437 \u0432\u043E\u0434\u044B):
704
- - \u0423\u043A\u0430\u0436\u0438 2-4 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u044B\u0445 \u0444\u0430\u043A\u0442\u043E\u0440\u0430 "\u0437\u0430" \u0438\u043B\u0438 "\u043F\u0440\u043E\u0442\u0438\u0432" \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0441\u0438\u0433\u043D\u0430\u043B\u0430 \u0432 "confirmations".
705
- - \u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u0443\u043F\u043E\u043C\u044F\u043D\u0438 \u0440\u043E\u043B\u044C \u043A\u043B\u044E\u0447\u0435\u0432\u043E\u0439 \u0444\u0438\u0433\u0443\u0440\u044B/\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B \u0441\u0435\u0442\u0430\u043F\u0430 (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 \u043F\u0440\u043E\u0431\u043E\u0439/\u0440\u0435\u0442\u0435\u0441\u0442/\u043B\u043E\u0436\u043D\u044B\u0439 \u043F\u0440\u043E\u0431\u043E\u0439/\u043A\u0430\u0441\u0430\u043D\u0438\u0435/\u043D\u0435\u0442 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F).
706
- - \u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u0443\u043F\u043E\u043C\u044F\u043D\u0438 BTC-\u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 (\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442, \u043D\u0435\u0439\u0442\u0440\u0430\u043B\u0435\u043D \u0438\u043B\u0438 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u0435\u0442).
707
- - \u041E\u0431\u044A\u044F\u0441\u043D\u0438, \u043F\u043E\u0447\u0435\u043C\u0443 quality \u0438\u043C\u0435\u043D\u043D\u043E \u0442\u0430\u043A\u043E\u0439.
708
- - \u0415\u0441\u043B\u0438 signal \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D (direction=null), \u043F\u0440\u044F\u043C\u043E \u0443\u043A\u0430\u0436\u0438 \u0447\u0442\u043E \u0434\u043E\u043B\u0436\u043D\u043E \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C\u0441\u044F \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0441\u0438\u0433\u043D\u0430\u043B\u0430.
709
- - \u0412 "retestPlan" \u043D\u0435 \u043F\u0438\u0448\u0438 \u0442\u0435\u0445\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0439 \u0448\u0430\u0431\u043B\u043E\u043D \u0432\u0440\u043E\u0434\u0435 "needRetest=false @ null"; \u043F\u0438\u0448\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u0447\u0435\u0441\u043A\u043E\u0435 \u043E\u0431\u044A\u044F\u0441\u043D\u0435\u043D\u0438\u0435.
710
- - \u041D\u0435 \u043F\u043E\u0432\u0442\u043E\u0440\u044F\u0439 \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u043E\u043B\u044F JSON; \u0434\u0430\u0439 \u0441\u043C\u044B\u0441\u043B \u0438 \u0440\u0435\u0448\u0435\u043D\u0438\u0435.
835
+ Requirements for useful structured analysis:
836
+ - Include 2-4 concrete factors for or against confirmation in \`confirmations\`.
837
+ - Explicitly mention the role of the key figure or structural state, for example breakout, retest, false break, touch, or lack of confirmation.
838
+ - Explicitly mention BTC context as supportive, neutral, or conflicting.
839
+ - Explain why the quality score is what it is.
840
+ - If the signal is not confirmed (\`direction=null\`), state clearly what must change for confirmation.
841
+ - In \`retestPlan\`, avoid technical placeholders like \`needRetest=false @ null\`; write a human explanation.
842
+ - Do not simply restate JSON fields; add interpretation and decision logic.
711
843
 
712
- \u041F\u0440\u0430\u0432\u0438\u043B\u0430 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u043E\u0431\u0440\u0435\u0437\u0430\u043D\u043D\u044B\u0445 \u0440\u044F\u0434\u043E\u0432 (last 5 values):
713
- - \u041D\u0435 \u0434\u0435\u043B\u0430\u0439 \u0441\u0438\u043B\u044C\u043D\u044B\u0445 \u0432\u044B\u0432\u043E\u0434\u043E\u0432 \u043E \u0434\u043E\u043B\u0433\u043E\u0441\u0440\u043E\u0447\u043D\u043E\u0439 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0435 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E 5 \u0442\u043E\u0447\u043A\u0430\u043C.
714
- - \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 4h/1d \u0440\u044F\u0434\u044B \u043A\u0430\u043A \u043A\u0440\u0430\u0442\u043A\u0438\u0439 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442, \u0430 \u043D\u0435 \u043A\u0430\u043A \u043F\u043E\u043B\u043D\u0443\u044E \u0438\u0441\u0442\u043E\u0440\u0438\u044E.
715
- - \u0415\u0441\u043B\u0438 \u0434\u0430\u043D\u043D\u044B\u0445 \u043C\u0430\u043B\u043E \u0434\u043B\u044F \u0443\u0432\u0435\u0440\u0435\u043D\u043D\u043E\u0433\u043E \u0432\u044B\u0432\u043E\u0434\u0430, \u0441\u043D\u0438\u0436\u0430\u0439 quality \u0438 \u0444\u043E\u0440\u043C\u0443\u043B\u0438\u0440\u0443\u0439 \u0432\u044B\u0432\u043E\u0434 \u043E\u0441\u0442\u043E\u0440\u043E\u0436\u043D\u043E.
844
+ Rules for using trimmed series (last 5 values):
845
+ - Do not make strong long-term conclusions from only 5 points.
846
+ - Use 4h and 1d series as brief context, not full history.
847
+ - If the data is too limited for confidence, reduce quality and use cautious wording.
716
848
 
717
- \u041A\u043E\u0440\u043E\u0442\u043A\u0438\u0435 \u043F\u0440\u0438\u043C\u0435\u0440\u044B (few-shot, \u0444\u043E\u0440\u043C\u0430\u0442 \u043E\u0442\u0432\u0435\u0442\u0430):
718
- {"direction":"LONG","quality":4,"needRetest":true,"retestPrice":100.2,"takeProfitPrice":101.5,"stopLossPrice":98.9,"setup":"\u0412\u0435\u0440\u043E\u044F\u0442\u043D\u044B\u0439 \u043F\u0440\u043E\u0431\u043E\u0439 \u0442\u0440\u0435\u043D\u0434\u043E\u0432\u043E\u0439 \u0432\u0432\u0435\u0440\u0445, \u043D\u043E \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0441\u0438\u0433\u043D\u0430\u043B\u0430 \u043D\u0443\u0436\u043D\u0430 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0443\u0440\u043E\u0432\u043D\u044F.","confirmations":"\u041F\u043E \u043C\u043E\u043D\u0435\u0442\u0435 \u0435\u0441\u0442\u044C \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0430 \u0438\u043C\u043F\u0443\u043B\u044C\u0441\u0430 \u0431\u0435\u0437 \u044F\u0432\u043D\u043E\u0433\u043E \u043F\u0435\u0440\u0435\u0433\u0440\u0435\u0432\u0430, \u043D\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0435\u0449\u0435 \u043D\u0435 \u0438\u0434\u0435\u0430\u043B\u044C\u043D\u043E\u0435.","btcContext":"BTC \u043D\u0435\u0439\u0442\u0440\u0430\u043B\u044C\u043D\u043E \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0438\u0434\u0435\u044E \u0438 \u043D\u0435 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u0435\u0442 \u0441 \u0442\u0435\u043A\u0443\u0449\u0438\u043C LONG-\u0441\u0438\u0433\u043D\u0430\u043B\u043E\u043C.","retestPlan":"\u041A\u043B\u044E\u0447\u0435\u0432\u043E\u0439 \u0443\u0440\u043E\u0432\u0435\u043D\u044C 100.2: \u0443\u0434\u0435\u0440\u0436\u0430\u043D\u0438\u0435 \u0432\u044B\u0448\u0435 \u043D\u0435\u0433\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0443 \u0441\u0438\u0433\u043D\u0430\u043B\u0430.","riskLevels":"\u041F\u0435\u0440\u0435\u0434\u0430\u043D\u043D\u044B\u0435 TP/SL \u0441\u0442\u043E\u044F\u0442 \u043F\u043E \u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u044B\u0435 \u0441\u0442\u043E\u0440\u043E\u043D\u044B \u043E\u0442 \u0442\u0435\u043A\u0443\u0449\u0435\u0439 \u0446\u0435\u043D\u044B \u0438 \u0432\u044B\u0433\u043B\u044F\u0434\u044F\u0442 \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u043E.","qualityReason":"Quality=4: \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u0445\u043E\u0440\u043E\u0448\u0430\u044F, \u043D\u043E \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u043E \u0443\u0440\u043E\u0432\u043D\u044E \u0435\u0449\u0435 \u0436\u0435\u043B\u0430\u0442\u0435\u043B\u044C\u043D\u043E.","triggerInvalidation":"\u0421\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442\u0441\u044F \u043F\u0440\u0438 \u0443\u0434\u0435\u0440\u0436\u0430\u043D\u0438\u0438 \u0443\u0440\u043E\u0432\u043D\u044F; \u0433\u0438\u043F\u043E\u0442\u0435\u0437\u0430 \u043E\u0441\u043B\u0430\u0431\u0435\u0432\u0430\u0435\u0442 \u043F\u0440\u0438 \u0432\u043E\u0437\u0432\u0440\u0430\u0442\u0435 \u043F\u043E\u0434 \u043B\u0438\u043D\u0438\u044E."}
719
- {"direction":null,"quality":2,"needRetest":false,"retestPrice":null,"takeProfitPrice":null,"stopLossPrice":null,"setup":"\u041A\u0430\u0441\u0430\u043D\u0438\u0435/\u0448\u0443\u043C \u0443 \u0442\u0440\u0435\u043D\u0434\u043E\u0432\u043E\u0439 \u0431\u0435\u0437 \u0443\u0432\u0435\u0440\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u0440\u043E\u0431\u043E\u044F.","confirmations":"\u0418\u043D\u0434\u0438\u043A\u0430\u0442\u043E\u0440\u044B \u0441\u043C\u0435\u0448\u0430\u043D\u043D\u044B\u0435 \u0438 \u043D\u0435 \u0434\u0430\u044E\u0442 \u0441\u0438\u043B\u044C\u043D\u043E\u0433\u043E \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u043E\u0433\u043E \u043F\u0440\u0435\u0438\u043C\u0443\u0449\u0435\u0441\u0442\u0432\u0430.","btcContext":"BTC \u0441\u043A\u043E\u0440\u0435\u0435 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u0435\u0442 \u0438\u043B\u0438 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u0435\u043A\u0443\u0449\u0443\u044E \u0433\u0438\u043F\u043E\u0442\u0435\u0437\u0443.","retestPlan":"\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0443\u0440\u043E\u0432\u0435\u043D\u044C \u043F\u043E\u043A\u0430 \u0440\u0430\u043D\u043E \u043E\u0446\u0435\u043D\u0438\u0432\u0430\u0442\u044C, \u043F\u043E\u0442\u043E\u043C\u0443 \u0447\u0442\u043E \u043D\u0435\u0442 \u0441\u0430\u043C\u043E\u0433\u043E \u0444\u0430\u043A\u0442\u0430 \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u0440\u043E\u0431\u043E\u044F.","riskLevels":"\u041F\u0435\u0440\u0435\u0434\u0430\u043D\u043D\u044B\u0435 \u0443\u0440\u043E\u0432\u043D\u0438 \u043F\u043E\u043A\u0430 \u043D\u0435 \u0441\u0442\u043E\u0438\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u044B\u043C\u0438 \u0438\u0437-\u0437\u0430 \u0441\u043B\u0430\u0431\u043E\u0439 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B.","qualityReason":"Quality=2: timing \u0441\u043B\u0430\u0431\u044B\u0439 \u0438 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0439 \u043C\u0430\u043B\u043E.","triggerInvalidation":"\u0416\u0434\u0430\u0442\u044C \u044F\u0432\u043D\u044B\u0439 \u043F\u0440\u043E\u0431\u043E\u0439 \u0438 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u043E \u043C\u043E\u043D\u0435\u0442\u0435 \u0438 BTC."}
849
+ Short few-shot examples:
850
+ {"direction":"LONG","quality":4,"needRetest":true,"retestPrice":100.2,"takeProfitPrice":101.5,"stopLossPrice":98.9,"setup":"Likely trendline breakout upward, but the signal still needs a level check for confirmation.","confirmations":"The coin shows momentum support without obvious overheating, but confirmation is not fully clean yet.","btcContext":"BTC is neutral-to-supportive and does not conflict with the current LONG signal.","retestPlan":"The key level is 100.2; holding above it would confirm the signal structure.","riskLevels":"The supplied TP and SL remain on the correct sides of the current price and still look internally coherent.","qualityReason":"Quality=4 because the structure is solid, but an extra level confirmation is still preferable.","triggerInvalidation":"The structure confirms on a hold above the level and weakens on a move back under the line."}
851
+ {"direction":null,"quality":2,"needRetest":false,"retestPrice":null,"takeProfitPrice":null,"stopLossPrice":null,"setup":"Touch or noise around the trendline without a convincing breakout.","confirmations":"Indicators are mixed and do not provide strong structural support.","btcContext":"BTC is either conflicting or not supportive of the current thesis.","retestPlan":"It is too early to define an extra level because a quality breakout is not present yet.","riskLevels":"The supplied levels should not be treated as confirmed while the structure remains weak.","qualityReason":"Quality=2 because timing is weak and confirmations are limited.","triggerInvalidation":"Wait for a clear breakout and confirmation from both the coin and BTC."}
720
852
 
721
- \u0412\u0435\u0440\u043D\u0438 \u0442\u043E\u043B\u044C\u043A\u043E JSON-\u043E\u0431\u044A\u0435\u043A\u0442, \u0431\u0435\u0437 \u043B\u0438\u0448\u043D\u0438\u0445 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432.
853
+ Return only the JSON object, with no extra characters.
722
854
  ${signal ? buildAiSystemPromptAddonByStrategy(signal) : ""}
723
855
  `;
724
856
  var buildAiPayload = (signal) => buildAiPayloadByStrategy(signal);
@@ -733,10 +865,10 @@ var getDeterministicAiGateContext = (payload) => {
733
865
  ) ?? null;
734
866
  };
735
867
  var buildAiHumanPrompt = (signal, payload = buildAiPayload(signal)) => `
736
- \u041F\u0440\u043E\u0430\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u0443\u0439 \u0443\u0436\u0435 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043D\u043D\u044B\u0439 \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0438\u0439 \u0441\u0438\u0433\u043D\u0430\u043B \u043F\u043E ${signal.symbol}. \u0418\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u0441\u0438\u0433\u043D\u0430\u043B \u0438\u043C\u0435\u0435\u0442 \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 ${signal.direction}.
737
- \u042D\u0442\u043E \u0437\u0430\u0434\u0430\u0447\u0430 \u043A\u043B\u0430\u0441\u0441\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438/\u0430\u0443\u0434\u0438\u0442\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B, \u0430 \u043D\u0435 \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u044F \u043A \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044E. \u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0438, \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442 \u043B\u0438 \u0442\u0435\u043A\u0443\u0449\u0430\u044F \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0439 \u0441\u0438\u0433\u043D\u0430\u043B, \u043D\u0430\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043E\u043D \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u043E \u0441\u0435\u0439\u0447\u0430\u0441, \u043D\u0443\u0436\u0435\u043D \u043B\u0438 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 confirmation level, \u0438 \u0432\u044B\u0433\u043B\u044F\u0434\u044F\u0442 \u043B\u0438 \u0443\u0436\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u043D\u044B\u0435 \u0432 payload.signal.prices \u0443\u0440\u043E\u0432\u043D\u0438 \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u043C\u0438. \u041D\u0435 \u0444\u043E\u0440\u043C\u0438\u0440\u0443\u0439 \u043D\u043E\u0432\u0443\u044E \u0433\u0438\u043F\u043E\u0442\u0435\u0437\u0443 \u0432\u043C\u0435\u0441\u0442\u043E \u0438\u0441\u0445\u043E\u0434\u043D\u043E\u0433\u043E \u0441\u0438\u0433\u043D\u0430\u043B\u0430 \u0438 \u043D\u0435 \u043F\u0440\u0438\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u043D\u043E\u0432\u044B\u0435 \u0443\u0440\u043E\u0432\u043D\u0438; \u0432\u0435\u0440\u043D\u0438 \u0442\u043E\u043B\u044C\u043A\u043E JSON \u0432 \u0437\u0430\u0434\u0430\u043D\u043D\u043E\u043C \u0444\u043E\u0440\u043C\u0430\u0442\u0435.
868
+ Analyze the already computed internal signal for ${signal.symbol}. The original signal direction is ${signal.direction}.
869
+ This is a structure-classification and audit task, not execution advice. Determine whether the current structure confirms the existing signal, how structurally coherent it is right now, whether an extra confirmation level is needed, and whether the already supplied levels in \`payload.signal.prices\` still look internally coherent. Do not replace the original thesis with a new one and do not invent new levels; return only the requested JSON.
738
870
 
739
- \u0414\u0430\u043D\u043D\u044B\u0435 \u0441\u0434\u0435\u043B\u043A\u0438:
871
+ Trade payload:
740
872
  ${JSON.stringify(payload)}
741
873
  ${buildAiHumanPromptAddonByStrategy(signal, payload)}
742
874
  `;
@@ -744,6 +876,14 @@ var DEFAULT_AI_MODEL = "openai/gpt-5-mini";
744
876
  var userSettingsCache = /* @__PURE__ */ new Map();
745
877
  var aiModelCache = /* @__PURE__ */ new Map();
746
878
  var getAiModelCacheKey = (userName, modelName) => `${userName}::${modelName}`;
879
+ var resolveAiModelName = (settings, requestedModelName) => {
880
+ const explicitModelName = typeof requestedModelName === "string" ? requestedModelName.trim() : "";
881
+ if (explicitModelName) {
882
+ return explicitModelName;
883
+ }
884
+ const settingsModelName = typeof settings.AI_MODEL === "string" ? settings.AI_MODEL.trim() : "";
885
+ return settingsModelName || DEFAULT_AI_MODEL;
886
+ };
747
887
  var getOpenRouterModelKwargs = (apiEndpoint) => {
748
888
  const endpoint = String(apiEndpoint ?? "").trim();
749
889
  if (!endpoint) {
@@ -774,30 +914,27 @@ var getAiSettings = async (userName = "root") => {
774
914
  userSettingsCache.set(userName, settingsPromise);
775
915
  }
776
916
  const settings = await settingsPromise;
777
- if (!settings.OPENAI_API_KEY || !settings.OPENAI_API_ENDPOINT) {
917
+ if (!settings.AI_API_KEY || !settings.AI_API_ENDPOINT) {
778
918
  throw new Error(`AI settings are incomplete for user ${userName}`);
779
919
  }
780
920
  return settings;
781
921
  };
782
- var createAiModel = async (userName = "root", modelName = DEFAULT_AI_MODEL) => {
922
+ var createAiModel = async (userName = "root", requestedModelName) => {
923
+ const settings = await getAiSettings(userName);
924
+ const modelName = resolveAiModelName(settings, requestedModelName);
783
925
  const cacheKey = getAiModelCacheKey(userName, modelName);
784
926
  let modelPromise = aiModelCache.get(cacheKey);
785
927
  if (!modelPromise) {
786
928
  modelPromise = (async () => {
787
- const [{ ChatOpenAI }, settings] = await Promise.all([
788
- import("@langchain/openai"),
789
- getAiSettings(userName)
790
- ]);
791
- const modelKwargs = getOpenRouterModelKwargs(
792
- settings.OPENAI_API_ENDPOINT
793
- );
929
+ const { ChatOpenAI } = await import("@langchain/openai");
930
+ const modelKwargs = getOpenRouterModelKwargs(settings.AI_API_ENDPOINT);
794
931
  return new ChatOpenAI({
795
932
  temperature: 0.2,
796
933
  modelName,
797
- apiKey: settings.OPENAI_API_KEY,
934
+ apiKey: settings.AI_API_KEY,
798
935
  ...Object.keys(modelKwargs).length ? { modelKwargs } : {},
799
936
  configuration: {
800
- baseURL: settings.OPENAI_API_ENDPOINT,
937
+ baseURL: settings.AI_API_ENDPOINT,
801
938
  defaultHeaders: {
802
939
  "HTTP-Referer": "https://tradejs.dev",
803
940
  "X-Title": "Inv"
@@ -812,11 +949,13 @@ var createAiModel = async (userName = "root", modelName = DEFAULT_AI_MODEL) => {
812
949
  }
813
950
  return modelPromise;
814
951
  };
815
- var getAiModel = async (userName = "root", modelName = DEFAULT_AI_MODEL) => {
952
+ var getAiModel = async (userName = "root", requestedModelName) => {
953
+ const settings = await getAiSettings(userName);
954
+ const resolvedModelName = resolveAiModelName(settings, requestedModelName);
816
955
  try {
817
- return await createAiModel(userName, modelName);
956
+ return await createAiModel(userName, resolvedModelName);
818
957
  } catch (error) {
819
- aiModelCache.delete(getAiModelCacheKey(userName, modelName));
958
+ aiModelCache.delete(getAiModelCacheKey(userName, resolvedModelName));
820
959
  userSettingsCache.delete(userName);
821
960
  throw error;
822
961
  }
@@ -839,12 +978,21 @@ var runAiPrompt = async ({ systemPrompt, humanPrompt }, options = {}) => {
839
978
  if (options.signal) {
840
979
  await ensureAiStrategyPluginsLoaded();
841
980
  }
842
- const [{ HumanMessage, SystemMessage }, model] = await Promise.all([
981
+ const [{ HumanMessage, SystemMessage }, model, settings] = await Promise.all([
843
982
  import("@langchain/core/messages"),
844
- getAiModel(options.userName, options.model)
983
+ getAiModel(options.userName, options.model),
984
+ getAiSettings(options.userName)
845
985
  ]);
846
986
  const messages = [];
987
+ const responseLanguage = (0, import_aiLanguages.getAiResponseLanguagePromptName)(
988
+ settings.AI_RESPONSE_LANGUAGE || import_aiLanguages.DEFAULT_AI_RESPONSE_LANGUAGE
989
+ );
847
990
  messages.push(new SystemMessage(systemPrompt));
991
+ messages.push(
992
+ new SystemMessage(
993
+ `Write all user-visible text fields in ${responseLanguage}. Keep field names and JSON syntax unchanged.`
994
+ )
995
+ );
848
996
  messages.push(
849
997
  new HumanMessage({
850
998
  content: [