@continuumdao/continuum-node-sdk 1.3.28 → 1.3.30

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 (215) hide show
  1. package/dist/agent-host-catalog.json +2 -0
  2. package/dist/core/chart/analysis/analysis-agent-view.d.ts.map +1 -1
  3. package/dist/core/chart/analysis/analysis-agent-view.js +34 -0
  4. package/dist/core/chart/analysis/analysis-agent-view.js.map +1 -1
  5. package/dist/core/chart/analysis/analysis-catalog.d.ts.map +1 -1
  6. package/dist/core/chart/analysis/analysis-catalog.js +16 -0
  7. package/dist/core/chart/analysis/analysis-catalog.js.map +1 -1
  8. package/dist/core/chart/analysis/analyze-tools.d.ts +47 -0
  9. package/dist/core/chart/analysis/analyze-tools.d.ts.map +1 -1
  10. package/dist/core/chart/analysis/analyze-tools.js +28 -9
  11. package/dist/core/chart/analysis/analyze-tools.js.map +1 -1
  12. package/dist/core/chart/analysis/bollinger-analyze-tools.d.ts +101 -0
  13. package/dist/core/chart/analysis/bollinger-analyze-tools.d.ts.map +1 -0
  14. package/dist/core/chart/analysis/bollinger-analyze-tools.js +289 -0
  15. package/dist/core/chart/analysis/bollinger-analyze-tools.js.map +1 -0
  16. package/dist/core/chart/analysis/bollinger-highlight.d.ts +29 -0
  17. package/dist/core/chart/analysis/bollinger-highlight.d.ts.map +1 -0
  18. package/dist/core/chart/analysis/bollinger-highlight.js +39 -0
  19. package/dist/core/chart/analysis/bollinger-highlight.js.map +1 -0
  20. package/dist/core/chart/analysis/candlestick-patterns-tools.d.ts +2 -0
  21. package/dist/core/chart/analysis/candlestick-patterns-tools.d.ts.map +1 -1
  22. package/dist/core/chart/analysis/candlestick-patterns-tools.js +16 -2
  23. package/dist/core/chart/analysis/candlestick-patterns-tools.js.map +1 -1
  24. package/dist/core/chart/analysis/chart-patterns-drawings-tools.d.ts +1 -0
  25. package/dist/core/chart/analysis/chart-patterns-drawings-tools.d.ts.map +1 -1
  26. package/dist/core/chart/analysis/chart-patterns-tools.d.ts +2 -0
  27. package/dist/core/chart/analysis/chart-patterns-tools.d.ts.map +1 -1
  28. package/dist/core/chart/analysis/chart-patterns-tools.js +2 -0
  29. package/dist/core/chart/analysis/chart-patterns-tools.js.map +1 -1
  30. package/dist/core/chart/analysis/key-fib-drawings-tools.d.ts +1 -0
  31. package/dist/core/chart/analysis/key-fib-drawings-tools.d.ts.map +1 -1
  32. package/dist/core/chart/analysis/key-fib-drawings-tools.js +48 -3
  33. package/dist/core/chart/analysis/key-fib-drawings-tools.js.map +1 -1
  34. package/dist/core/chart/analysis/key-level-drawings-tools.d.ts.map +1 -1
  35. package/dist/core/chart/analysis/key-level-drawings-tools.js +12 -1
  36. package/dist/core/chart/analysis/key-level-drawings-tools.js.map +1 -1
  37. package/dist/core/chart/analysis/moving-averages-analyze-tools.d.ts +116 -0
  38. package/dist/core/chart/analysis/moving-averages-analyze-tools.d.ts.map +1 -0
  39. package/dist/core/chart/analysis/moving-averages-analyze-tools.js +205 -0
  40. package/dist/core/chart/analysis/moving-averages-analyze-tools.js.map +1 -0
  41. package/dist/core/chart/analysis/moving-averages-highlight.d.ts +30 -0
  42. package/dist/core/chart/analysis/moving-averages-highlight.d.ts.map +1 -0
  43. package/dist/core/chart/analysis/moving-averages-highlight.js +77 -0
  44. package/dist/core/chart/analysis/moving-averages-highlight.js.map +1 -0
  45. package/dist/core/chart/analysis/trade-setups/bollinger-trade-setup.d.ts +77 -0
  46. package/dist/core/chart/analysis/trade-setups/bollinger-trade-setup.d.ts.map +1 -0
  47. package/dist/core/chart/analysis/trade-setups/bollinger-trade-setup.js +163 -0
  48. package/dist/core/chart/analysis/trade-setups/bollinger-trade-setup.js.map +1 -0
  49. package/dist/core/chart/analysis/trade-setups/build-trade-uniswap.d.ts.map +1 -1
  50. package/dist/core/chart/analysis/trade-setups/build-trade-uniswap.js +1 -0
  51. package/dist/core/chart/analysis/trade-setups/build-trade-uniswap.js.map +1 -1
  52. package/dist/core/chart/analysis/trade-setups/build-trade.d.ts +4 -1
  53. package/dist/core/chart/analysis/trade-setups/build-trade.d.ts.map +1 -1
  54. package/dist/core/chart/analysis/trade-setups/build-trade.js +36 -12
  55. package/dist/core/chart/analysis/trade-setups/build-trade.js.map +1 -1
  56. package/dist/core/chart/analysis/trade-setups/candlestick-trade-setup.d.ts +3 -3
  57. package/dist/core/chart/analysis/trade-setups/candlestick-trade-setup.d.ts.map +1 -1
  58. package/dist/core/chart/analysis/trade-setups/candlestick-trade-setup.js +12 -14
  59. package/dist/core/chart/analysis/trade-setups/candlestick-trade-setup.js.map +1 -1
  60. package/dist/core/chart/analysis/trade-setups/chart-data-purpose.d.ts +20 -0
  61. package/dist/core/chart/analysis/trade-setups/chart-data-purpose.d.ts.map +1 -0
  62. package/dist/core/chart/analysis/trade-setups/chart-data-purpose.js +207 -0
  63. package/dist/core/chart/analysis/trade-setups/chart-data-purpose.js.map +1 -0
  64. package/dist/core/chart/analysis/trade-setups/chart-pattern-trade-setup.d.ts +7 -1
  65. package/dist/core/chart/analysis/trade-setups/chart-pattern-trade-setup.d.ts.map +1 -1
  66. package/dist/core/chart/analysis/trade-setups/chart-pattern-trade-setup.js +24 -2
  67. package/dist/core/chart/analysis/trade-setups/chart-pattern-trade-setup.js.map +1 -1
  68. package/dist/core/chart/analysis/trade-setups/entry-proximity-atr.d.ts +3 -0
  69. package/dist/core/chart/analysis/trade-setups/entry-proximity-atr.d.ts.map +1 -0
  70. package/dist/core/chart/analysis/trade-setups/entry-proximity-atr.js +32 -0
  71. package/dist/core/chart/analysis/trade-setups/entry-proximity-atr.js.map +1 -0
  72. package/dist/core/chart/analysis/trade-setups/index.d.ts +3 -0
  73. package/dist/core/chart/analysis/trade-setups/index.d.ts.map +1 -1
  74. package/dist/core/chart/analysis/trade-setups/index.js +3 -0
  75. package/dist/core/chart/analysis/trade-setups/index.js.map +1 -1
  76. package/dist/core/chart/analysis/trade-setups/key-level-fib-retrace-trade-setup.d.ts +8 -0
  77. package/dist/core/chart/analysis/trade-setups/key-level-fib-retrace-trade-setup.d.ts.map +1 -1
  78. package/dist/core/chart/analysis/trade-setups/key-level-fib-retrace-trade-setup.js +33 -5
  79. package/dist/core/chart/analysis/trade-setups/key-level-fib-retrace-trade-setup.js.map +1 -1
  80. package/dist/core/chart/analysis/trade-setups/key-levels-trade-setup.d.ts +7 -0
  81. package/dist/core/chart/analysis/trade-setups/key-levels-trade-setup.d.ts.map +1 -1
  82. package/dist/core/chart/analysis/trade-setups/key-levels-trade-setup.js +47 -20
  83. package/dist/core/chart/analysis/trade-setups/key-levels-trade-setup.js.map +1 -1
  84. package/dist/core/chart/analysis/trade-setups/moving-averages-trade-setup.d.ts +110 -0
  85. package/dist/core/chart/analysis/trade-setups/moving-averages-trade-setup.d.ts.map +1 -0
  86. package/dist/core/chart/analysis/trade-setups/moving-averages-trade-setup.js +330 -0
  87. package/dist/core/chart/analysis/trade-setups/moving-averages-trade-setup.js.map +1 -0
  88. package/dist/core/chart/analysis/trade-setups/pattern-limit-entry.d.ts +10 -1
  89. package/dist/core/chart/analysis/trade-setups/pattern-limit-entry.d.ts.map +1 -1
  90. package/dist/core/chart/analysis/trade-setups/pattern-limit-entry.js +75 -34
  91. package/dist/core/chart/analysis/trade-setups/pattern-limit-entry.js.map +1 -1
  92. package/dist/core/chart/analysis/trade-setups/shared.d.ts +1 -1
  93. package/dist/core/chart/analysis/trade-setups/shared.d.ts.map +1 -1
  94. package/dist/core/chart/analysis/trade-setups/shared.js +4 -0
  95. package/dist/core/chart/analysis/trade-setups/shared.js.map +1 -1
  96. package/dist/core/chart/analysis/trade-setups/trade-desk-defaults.d.ts +8 -0
  97. package/dist/core/chart/analysis/trade-setups/trade-desk-defaults.d.ts.map +1 -1
  98. package/dist/core/chart/analysis/trade-setups/trade-desk-defaults.js +9 -1
  99. package/dist/core/chart/analysis/trade-setups/trade-desk-defaults.js.map +1 -1
  100. package/dist/core/chart/analysis/trade-setups/trade-desk-universal-input.d.ts +16 -0
  101. package/dist/core/chart/analysis/trade-setups/trade-desk-universal-input.d.ts.map +1 -0
  102. package/dist/core/chart/analysis/trade-setups/trade-desk-universal-input.js +24 -0
  103. package/dist/core/chart/analysis/trade-setups/trade-desk-universal-input.js.map +1 -0
  104. package/dist/core/chart/analysis/trade-setups/trade-entry-gates.d.ts +9 -5
  105. package/dist/core/chart/analysis/trade-setups/trade-entry-gates.d.ts.map +1 -1
  106. package/dist/core/chart/analysis/trade-setups/trade-entry-gates.js +24 -8
  107. package/dist/core/chart/analysis/trade-setups/trade-entry-gates.js.map +1 -1
  108. package/dist/core/chart/analysis/trade-setups/trade-idea-list.d.ts +21 -0
  109. package/dist/core/chart/analysis/trade-setups/trade-idea-list.d.ts.map +1 -1
  110. package/dist/core/chart/analysis/trade-setups/trade-idea-list.js +52 -0
  111. package/dist/core/chart/analysis/trade-setups/trade-idea-list.js.map +1 -1
  112. package/dist/core/chart/analysis/trade-setups/trade-idea.d.ts +20 -0
  113. package/dist/core/chart/analysis/trade-setups/trade-idea.d.ts.map +1 -1
  114. package/dist/core/chart/analysis/trade-setups/trade-idea.js +20 -0
  115. package/dist/core/chart/analysis/trade-setups/trade-idea.js.map +1 -1
  116. package/dist/core/chart/analysis/trade-setups/trade-purpose-format.d.ts +2 -0
  117. package/dist/core/chart/analysis/trade-setups/trade-purpose-format.d.ts.map +1 -1
  118. package/dist/core/chart/analysis/trade-setups/trade-purpose-format.js +5 -0
  119. package/dist/core/chart/analysis/trade-setups/trade-purpose-format.js.map +1 -1
  120. package/dist/core/chart/analysis/trade-setups/trade-setup-selection.d.ts +122 -0
  121. package/dist/core/chart/analysis/trade-setups/trade-setup-selection.d.ts.map +1 -0
  122. package/dist/core/chart/analysis/trade-setups/trade-setup-selection.js +231 -0
  123. package/dist/core/chart/analysis/trade-setups/trade-setup-selection.js.map +1 -0
  124. package/dist/core/chart/analysis/trade-setups/trend-structure-trade-setup.d.ts.map +1 -1
  125. package/dist/core/chart/analysis/trade-setups/trend-structure-trade-setup.js +12 -3
  126. package/dist/core/chart/analysis/trade-setups/trend-structure-trade-setup.js.map +1 -1
  127. package/dist/core/chart/analysis/trend-line-menu-summary.d.ts +9 -2
  128. package/dist/core/chart/analysis/trend-line-menu-summary.d.ts.map +1 -1
  129. package/dist/core/chart/analysis/trend-line-menu-summary.js +74 -6
  130. package/dist/core/chart/analysis/trend-line-menu-summary.js.map +1 -1
  131. package/dist/core/chart/display-downsample.d.ts +1 -1
  132. package/dist/core/chart/display-downsample.d.ts.map +1 -1
  133. package/dist/core/chart/display-downsample.js +21 -0
  134. package/dist/core/chart/display-downsample.js.map +1 -1
  135. package/dist/core/chart/overlay-schemas.d.ts +3 -0
  136. package/dist/core/chart/overlay-schemas.d.ts.map +1 -1
  137. package/dist/core/chart/overlay-schemas.js +2 -0
  138. package/dist/core/chart/overlay-schemas.js.map +1 -1
  139. package/dist/core/chart/overlays.d.ts.map +1 -1
  140. package/dist/core/chart/overlays.js +21 -0
  141. package/dist/core/chart/overlays.js.map +1 -1
  142. package/dist/core/chart/prepare-core.d.ts.map +1 -1
  143. package/dist/core/chart/prepare-core.js +20 -1
  144. package/dist/core/chart/prepare-core.js.map +1 -1
  145. package/dist/core/chart/prepare-from-rows.d.ts +2 -0
  146. package/dist/core/chart/prepare-from-rows.d.ts.map +1 -1
  147. package/dist/core/chart/schemas.d.ts +9 -0
  148. package/dist/core/chart/schemas.d.ts.map +1 -1
  149. package/dist/core/chart/schemas.js +1 -1
  150. package/dist/core/chart/schemas.js.map +1 -1
  151. package/dist/core/chart-patterns/recommendation.d.ts +1 -0
  152. package/dist/core/chart-patterns/recommendation.d.ts.map +1 -1
  153. package/dist/core/chart-patterns/recommendation.js +7 -1
  154. package/dist/core/chart-patterns/recommendation.js.map +1 -1
  155. package/dist/core/chart-patterns/scan.d.ts.map +1 -1
  156. package/dist/core/chart-patterns/scan.js +4 -1
  157. package/dist/core/chart-patterns/scan.js.map +1 -1
  158. package/dist/core/chart-patterns/types.d.ts +2 -0
  159. package/dist/core/chart-patterns/types.d.ts.map +1 -1
  160. package/dist/core/mpc/schemas.d.ts +4 -0
  161. package/dist/core/mpc/schemas.d.ts.map +1 -1
  162. package/dist/core/mpc/schemas.js +3 -0
  163. package/dist/core/mpc/schemas.js.map +1 -1
  164. package/dist/core/mpc/sign-request-utils.d.ts +6 -0
  165. package/dist/core/mpc/sign-request-utils.d.ts.map +1 -1
  166. package/dist/core/mpc/sign-request-utils.js +47 -0
  167. package/dist/core/mpc/sign-request-utils.js.map +1 -1
  168. package/dist/core/mpc/sign-result-summary.d.ts.map +1 -1
  169. package/dist/core/mpc/sign-result-summary.js +5 -1
  170. package/dist/core/mpc/sign-result-summary.js.map +1 -1
  171. package/dist/core/mpc/types.d.ts +4 -0
  172. package/dist/core/mpc/types.d.ts.map +1 -1
  173. package/dist/index.d.ts +1 -1
  174. package/dist/index.d.ts.map +1 -1
  175. package/dist/index.js +1 -1
  176. package/dist/index.js.map +1 -1
  177. package/dist/mcp/agent-environment-variables.js +1 -1
  178. package/dist/mcp/agent-environment-variables.js.map +1 -1
  179. package/dist/mcp/chart.d.ts.map +1 -1
  180. package/dist/mcp/chart.js +14 -0
  181. package/dist/mcp/chart.js.map +1 -1
  182. package/dist/mcp/deferred/tool-group-map.d.ts.map +1 -1
  183. package/dist/mcp/deferred/tool-group-map.js +2 -0
  184. package/dist/mcp/deferred/tool-group-map.js.map +1 -1
  185. package/dist/mcp/defi/defi-protocol-fetch-meta.d.ts +3 -0
  186. package/dist/mcp/defi/defi-protocol-fetch-meta.d.ts.map +1 -1
  187. package/dist/mcp/defi/defi-protocol-fetch-meta.js +26 -18
  188. package/dist/mcp/defi/defi-protocol-fetch-meta.js.map +1 -1
  189. package/dist/mcp/defi/discovery.js +1 -1
  190. package/dist/mcp/defi/discovery.js.map +1 -1
  191. package/dist/mcp/defi/handler.d.ts.map +1 -1
  192. package/dist/mcp/defi/handler.js +13 -2
  193. package/dist/mcp/defi/handler.js.map +1 -1
  194. package/dist/mcp/defi/register-protocol-tools.d.ts.map +1 -1
  195. package/dist/mcp/defi/register-protocol-tools.js +4 -1
  196. package/dist/mcp/defi/register-protocol-tools.js.map +1 -1
  197. package/dist/mcp/defi/the-graph-api-key.d.ts +17 -0
  198. package/dist/mcp/defi/the-graph-api-key.d.ts.map +1 -0
  199. package/dist/mcp/defi/the-graph-api-key.js +82 -0
  200. package/dist/mcp/defi/the-graph-api-key.js.map +1 -0
  201. package/dist/mcp/defi/uniswap-v4-ohlcv-chains.d.ts +7 -0
  202. package/dist/mcp/defi/uniswap-v4-ohlcv-chains.d.ts.map +1 -0
  203. package/dist/mcp/defi/uniswap-v4-ohlcv-chains.js +11 -0
  204. package/dist/mcp/defi/uniswap-v4-ohlcv-chains.js.map +1 -0
  205. package/dist/mcp/mpc.js +2 -2
  206. package/dist/mcp/mpc.js.map +1 -1
  207. package/dist/mcp/ohlcv-session-wrapper.d.ts.map +1 -1
  208. package/dist/mcp/ohlcv-session-wrapper.js +1 -0
  209. package/dist/mcp/ohlcv-session-wrapper.js.map +1 -1
  210. package/dist/mcp/resources/chart-analysis.md +4 -1
  211. package/dist/mcp/resources/chart.md +3 -2
  212. package/dist/mcp/trade-tools.d.ts.map +1 -1
  213. package/dist/mcp/trade-tools.js +9 -1
  214. package/dist/mcp/trade-tools.js.map +1 -1
  215. package/package.json +2 -2
@@ -0,0 +1,330 @@
1
+ import { isFiniteTradePrice } from './shared.js';
2
+ import { entryProximityAtrFromOhlcvRows } from './entry-proximity-atr.js';
3
+ import { assessTradeSetupEntryActionability } from './trade-entry-gates.js';
4
+ import { tradeDeskConfig } from './trade-desk-defaults.js';
5
+ export const DEFAULT_MA_FAST_PERIOD = 50;
6
+ export const DEFAULT_MA_SLOW_PERIOD = 200;
7
+ export const DEFAULT_MA_TYPE = 'sma';
8
+ export const DEFAULT_FRESH_CROSSOVER_MAX_BARS = 5;
9
+ const MIN_CLEAR_CONFIDENCE = 0.45;
10
+ export function maPairLabel(maType, fastPeriod, slowPeriod) {
11
+ const prefix = maType === 'ema' ? 'EMA' : 'SMA';
12
+ return `${prefix}(${fastPeriod})/${prefix}(${slowPeriod})`;
13
+ }
14
+ function sideFromRegime(fastMa, slowMa) {
15
+ if (fastMa > slowMa) {
16
+ return 'long';
17
+ }
18
+ if (fastMa < slowMa) {
19
+ return 'short';
20
+ }
21
+ return 'neutral';
22
+ }
23
+ function crossoverLabelFromState(state) {
24
+ if (state === 'bullish') {
25
+ return 'golden_cross';
26
+ }
27
+ if (state === 'bearish') {
28
+ return 'death_cross';
29
+ }
30
+ return 'none';
31
+ }
32
+ function proximityTypeFromSide(side) {
33
+ if (side === 'long') {
34
+ return 'slow_ma_retest_bullish';
35
+ }
36
+ if (side === 'short') {
37
+ return 'slow_ma_retest_bearish';
38
+ }
39
+ return 'none';
40
+ }
41
+ function crossoverConfidence(barsSinceCrossover, fastMa, slowMa) {
42
+ let confidence = 0.45;
43
+ if (barsSinceCrossover != null && barsSinceCrossover <= 2) {
44
+ confidence += 0.1;
45
+ }
46
+ else if (barsSinceCrossover != null && barsSinceCrossover <= 5) {
47
+ confidence += 0.05;
48
+ }
49
+ const spread = Math.abs(fastMa - slowMa);
50
+ const mid = (fastMa + slowMa) / 2;
51
+ if (mid > 0 && spread / mid > 0.002) {
52
+ confidence = Math.min(0.75, confidence + 0.05);
53
+ }
54
+ return confidence;
55
+ }
56
+ function retestConfidence(fastMa, slowMa) {
57
+ const spread = Math.abs(fastMa - slowMa);
58
+ const mid = (fastMa + slowMa) / 2;
59
+ let confidence = 0.45;
60
+ if (mid > 0 && spread / mid > 0.003) {
61
+ confidence = Math.min(0.65, confidence + 0.07);
62
+ }
63
+ return confidence;
64
+ }
65
+ function formatCrossoverAge(barsSinceCrossover) {
66
+ if (barsSinceCrossover == null) {
67
+ return '';
68
+ }
69
+ if (barsSinceCrossover === 0) {
70
+ return '';
71
+ }
72
+ return ` ${barsSinceCrossover} bar${barsSinceCrossover === 1 ? '' : 's'} ago`;
73
+ }
74
+ export function buildMovingAveragesTradeSummary(input) {
75
+ const pair = maPairLabel(input.maType, input.fastPeriod, input.slowPeriod);
76
+ if (input.strategy === 'crossover') {
77
+ const crossName = input.crossoverLabel === 'golden_cross' ? 'Golden cross' : 'Death cross';
78
+ const age = formatCrossoverAge(input.barsSinceCrossover);
79
+ if (input.status === 'clear' && input.side !== 'neutral') {
80
+ const sideWord = input.side === 'long' ? 'long' : 'short';
81
+ return `${crossName}${age} · ${pair} · ${sideWord} entry at last close`;
82
+ }
83
+ return `${crossName}${age} · ${pair} · no actionable entry`;
84
+ }
85
+ const regime = input.proximityType === 'slow_ma_retest_bullish'
86
+ ? 'bullish regime'
87
+ : input.proximityType === 'slow_ma_retest_bearish'
88
+ ? 'bearish regime'
89
+ : 'neutral regime';
90
+ const slowLabel = `${input.maType === 'ema' ? 'EMA' : 'SMA'}(${input.slowPeriod})`;
91
+ if (input.status === 'clear' && input.side !== 'neutral') {
92
+ const sideWord = input.side === 'long' ? 'long' : 'short';
93
+ return `Proximity + retest · ${regime} · ${sideWord} limit at ${slowLabel}`;
94
+ }
95
+ if (input.unclearReason?.includes('proximity')) {
96
+ return `Proximity + retest · ${regime} · price not within proximity of ${slowLabel}`;
97
+ }
98
+ return `Proximity + retest · ${regime} · no actionable entry`;
99
+ }
100
+ export function detectMaCrossover(fastSeries, slowSeries) {
101
+ const len = Math.min(fastSeries.length, slowSeries.length);
102
+ if (len < 2) {
103
+ return { crossoverState: 'none', barsSinceCrossover: null };
104
+ }
105
+ for (let offset = 0; offset < len - 1; offset++) {
106
+ const i = len - 1 - offset;
107
+ const prev = i - 1;
108
+ const fast = fastSeries[i];
109
+ const slow = slowSeries[i];
110
+ const fastPrev = fastSeries[prev];
111
+ const slowPrev = slowSeries[prev];
112
+ if (!isFiniteTradePrice(fast) ||
113
+ !isFiniteTradePrice(slow) ||
114
+ !isFiniteTradePrice(fastPrev) ||
115
+ !isFiniteTradePrice(slowPrev)) {
116
+ continue;
117
+ }
118
+ if (fast > slow && fastPrev <= slowPrev) {
119
+ return { crossoverState: 'bullish', barsSinceCrossover: offset };
120
+ }
121
+ if (fast < slow && fastPrev >= slowPrev) {
122
+ return { crossoverState: 'bearish', barsSinceCrossover: offset };
123
+ }
124
+ }
125
+ return { crossoverState: 'none', barsSinceCrossover: null };
126
+ }
127
+ export function buildMovingAveragesTradeSetup(input) {
128
+ const close = input.lastClose;
129
+ const fastMa = input.fastMa;
130
+ const slowMa = input.slowMa;
131
+ if (!isFiniteTradePrice(close) || !isFiniteTradePrice(fastMa) || !isFiniteTradePrice(slowMa)) {
132
+ return null;
133
+ }
134
+ const desk = tradeDeskConfig({
135
+ entryProximityPct: input.entryProximityPct,
136
+ entryProximityMode: input.entryProximityMode,
137
+ entryProximityAtrPeriod: input.entryProximityAtrPeriod,
138
+ entryOffsetPct: input.entryOffsetPct,
139
+ });
140
+ const freshMax = input.freshCrossoverMaxBars ?? DEFAULT_FRESH_CROSSOVER_MAX_BARS;
141
+ const regimeSide = sideFromRegime(fastMa, slowMa);
142
+ const crossoverLabel = crossoverLabelFromState(input.crossoverState);
143
+ const proximityType = proximityTypeFromSide(regimeSide);
144
+ const atrAtLastBar = desk.entryProximityMode === 'atr' && input.bars?.length
145
+ ? entryProximityAtrFromOhlcvRows(input.bars, desk.entryProximityAtrPeriod)
146
+ : null;
147
+ const freshCrossover = input.crossoverState !== 'none' &&
148
+ input.barsSinceCrossover != null &&
149
+ input.barsSinceCrossover <= freshMax;
150
+ let strategy = 'proximity_retest';
151
+ let side = regimeSide;
152
+ let status = 'unclear';
153
+ let confidence = 0.35;
154
+ let entryPrice;
155
+ let entryLabel;
156
+ let entryOffsetMode = 'retest';
157
+ let setupPurposeCode = 'ma-ret';
158
+ let unclearReason = regimeSide === 'neutral'
159
+ ? 'Fast and slow moving averages are aligned — no directional regime.'
160
+ : 'No actionable moving-average setup on the current bar.';
161
+ if (freshCrossover && input.crossoverState === 'bullish') {
162
+ strategy = 'crossover';
163
+ side = 'long';
164
+ confidence = crossoverConfidence(input.barsSinceCrossover, fastMa, slowMa);
165
+ entryOffsetMode = 'bounce';
166
+ setupPurposeCode = 'ma-cross';
167
+ if (confidence >= MIN_CLEAR_CONFIDENCE) {
168
+ status = 'clear';
169
+ entryPrice = close;
170
+ entryLabel = 'last close (crossover)';
171
+ unclearReason = '';
172
+ }
173
+ }
174
+ else if (freshCrossover && input.crossoverState === 'bearish') {
175
+ strategy = 'crossover';
176
+ side = 'short';
177
+ confidence = crossoverConfidence(input.barsSinceCrossover, fastMa, slowMa);
178
+ entryOffsetMode = 'bounce';
179
+ setupPurposeCode = 'ma-cross';
180
+ if (confidence >= MIN_CLEAR_CONFIDENCE) {
181
+ status = 'clear';
182
+ entryPrice = close;
183
+ entryLabel = 'last close (crossover)';
184
+ unclearReason = '';
185
+ }
186
+ }
187
+ else if (input.crossoverState !== 'none' &&
188
+ input.barsSinceCrossover != null &&
189
+ input.barsSinceCrossover > freshMax) {
190
+ strategy = 'crossover';
191
+ side = input.crossoverState === 'bullish' ? 'long' : 'short';
192
+ confidence = crossoverConfidence(input.barsSinceCrossover, fastMa, slowMa);
193
+ entryOffsetMode = 'bounce';
194
+ setupPurposeCode = 'ma-cross';
195
+ unclearReason = `Crossover occurred ${input.barsSinceCrossover} bars ago — outside fresh window (${freshMax} bars).`;
196
+ }
197
+ else if (regimeSide !== 'neutral') {
198
+ strategy = 'proximity_retest';
199
+ side = regimeSide;
200
+ confidence = retestConfidence(fastMa, slowMa);
201
+ entryOffsetMode = 'retest';
202
+ setupPurposeCode = 'ma-ret';
203
+ const entryCheck = assessTradeSetupEntryActionability({
204
+ lastClose: close,
205
+ entryPrice: slowMa,
206
+ side,
207
+ entryOffsetMode: 'retest',
208
+ entryProximityPct: desk.entryProximityPct,
209
+ entryProximityMode: desk.entryProximityMode,
210
+ entryProximityAtr: atrAtLastBar,
211
+ entryOffsetPct: desk.entryOffsetPct,
212
+ });
213
+ if (entryCheck.ok && confidence >= MIN_CLEAR_CONFIDENCE) {
214
+ status = 'clear';
215
+ entryPrice = slowMa;
216
+ entryLabel = `${input.maType === 'ema' ? 'EMA' : 'SMA'}(${input.slowPeriod}) retest`;
217
+ unclearReason = '';
218
+ confidence = Math.min(0.7, confidence + 0.05);
219
+ }
220
+ else if (!entryCheck.ok) {
221
+ unclearReason = entryCheck.unclearReason;
222
+ }
223
+ }
224
+ const targetPrice = status === 'clear' && side === 'long'
225
+ ? fastMa
226
+ : status === 'clear' && side === 'short'
227
+ ? fastMa
228
+ : undefined;
229
+ const targetLabel = status === 'clear' ? `${input.maType === 'ema' ? 'EMA' : 'SMA'}(${input.fastPeriod})` : undefined;
230
+ const invalidationPrice = status === 'clear' && side === 'long'
231
+ ? slowMa
232
+ : status === 'clear' && side === 'short'
233
+ ? slowMa
234
+ : undefined;
235
+ const invalidationLabel = status === 'clear'
236
+ ? `below ${input.maType === 'ema' ? 'EMA' : 'SMA'}(${input.slowPeriod})`
237
+ : undefined;
238
+ const tradeSummary = buildMovingAveragesTradeSummary({
239
+ maType: input.maType,
240
+ fastPeriod: input.fastPeriod,
241
+ slowPeriod: input.slowPeriod,
242
+ strategy,
243
+ crossoverLabel: strategy === 'crossover' ? crossoverLabel : 'none',
244
+ proximityType: strategy === 'proximity_retest' ? proximityType : 'none',
245
+ side,
246
+ status,
247
+ barsSinceCrossover: input.barsSinceCrossover,
248
+ unclearReason,
249
+ });
250
+ const conditionalNote = status === 'clear'
251
+ ? tradeSummary
252
+ : strategy === 'crossover' && crossoverLabel !== 'none'
253
+ ? `${crossoverLabel === 'golden_cross' ? 'Golden cross' : 'Death cross'} detected but not actionable — ${unclearReason || 'wait for a fresh crossover or proximity retest.'}`
254
+ : unclearReason ||
255
+ 'Moving-average setup is unclear — wait for crossover or slow MA retest within proximity.';
256
+ return {
257
+ status,
258
+ source: 'moving_averages',
259
+ lastClose: close,
260
+ fastMa,
261
+ slowMa,
262
+ fastPeriod: input.fastPeriod,
263
+ slowPeriod: input.slowPeriod,
264
+ maType: input.maType,
265
+ crossoverState: input.crossoverState,
266
+ barsSinceCrossover: input.barsSinceCrossover,
267
+ strategy,
268
+ crossoverLabel: strategy === 'crossover' ? crossoverLabel : 'none',
269
+ proximityType: strategy === 'proximity_retest' ? proximityType : 'none',
270
+ setupPurposeCode,
271
+ entryOffsetMode,
272
+ entryProximityPct: desk.entryProximityPct,
273
+ entryProximityMode: desk.entryProximityMode,
274
+ entryOffsetPct: desk.entryOffsetPct,
275
+ invalidationOffsetPct: desk.invalidationOffsetPct,
276
+ ...(atrAtLastBar != null ? { atrAtLastBar } : {}),
277
+ side,
278
+ confidence,
279
+ tradeSummary,
280
+ conditionalNote,
281
+ ...(status === 'clear' && entryPrice != null && entryLabel
282
+ ? { entryPrice, entryLabel }
283
+ : {}),
284
+ ...(targetPrice != null && targetLabel ? { targetPrice, targetLabel } : {}),
285
+ ...(invalidationPrice != null && invalidationLabel
286
+ ? { invalidationPrice, invalidationLabel }
287
+ : {}),
288
+ ...(unclearReason && status === 'unclear' ? { unclearReason } : {}),
289
+ };
290
+ }
291
+ export function movingAveragesTradeIdeaContextFromSetup(setup) {
292
+ return {
293
+ tradeSummary: setup.tradeSummary,
294
+ strategy: setup.strategy,
295
+ crossoverLabel: setup.crossoverLabel,
296
+ proximityType: setup.proximityType,
297
+ fastPeriod: setup.fastPeriod,
298
+ slowPeriod: setup.slowPeriod,
299
+ maType: setup.maType,
300
+ barsSinceCrossover: setup.barsSinceCrossover,
301
+ setupPurposeCode: setup.setupPurposeCode,
302
+ };
303
+ }
304
+ export function normalizeMovingAveragesTradeSetup(setup) {
305
+ return {
306
+ status: setup.status,
307
+ side: setup.side,
308
+ confidence: setup.confidence,
309
+ lastClose: setup.lastClose,
310
+ entry: setup.status === 'clear' &&
311
+ setup.side !== 'neutral' &&
312
+ setup.entryPrice != null &&
313
+ isFiniteTradePrice(setup.entryPrice)
314
+ ? { price: setup.entryPrice, label: setup.entryLabel ?? 'MA entry' }
315
+ : undefined,
316
+ ...(setup.targetPrice != null && isFiniteTradePrice(setup.targetPrice)
317
+ ? { target: { price: setup.targetPrice, label: setup.targetLabel ?? 'fast MA' } }
318
+ : {}),
319
+ ...(setup.invalidationPrice != null && isFiniteTradePrice(setup.invalidationPrice)
320
+ ? {
321
+ invalidation: {
322
+ price: setup.invalidationPrice,
323
+ label: setup.invalidationLabel ?? 'slow MA breach',
324
+ },
325
+ }
326
+ : {}),
327
+ unclearReason: setup.unclearReason,
328
+ };
329
+ }
330
+ //# sourceMappingURL=moving-averages-trade-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moving-averages-trade-setup.js","sourceRoot":"","sources":["../../../../../src/core/chart/analysis/trade-setups/moving-averages-trade-setup.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,13 @@ import type { PatternKeyLevelSummary } from '../../../chart-patterns/pattern-men
3
3
  import type { TradeSetupSide } from './shared.js';
4
4
  export declare const DEFAULT_BREAK_TOLERANCE_PCT = 0.1;
5
5
  export declare const DEFAULT_ENTRY_PROXIMITY_PCT = 1;
6
+ export type EntryProximityMode = 'price' | 'atr';
7
+ export declare const DEFAULT_ENTRY_PROXIMITY_MODE: EntryProximityMode;
8
+ export type WithinEntryProximityOptions = {
9
+ mode?: EntryProximityMode;
10
+ atr?: number | null;
11
+ };
12
+ export declare function entryProximityGateLabel(pct: number, mode?: EntryProximityMode): string;
6
13
  export type PatternEntryPhase = 'inside_pattern' | 'post_breakout_retest';
7
14
  export type EntryOffsetMode = 'bounce' | 'retest';
8
15
  export type PatternPhase = 'inside' | 'broken_above' | 'broken_below';
@@ -22,6 +29,8 @@ export type ResolvePatternLimitInput = {
22
29
  classificationSide: TradeSetupSide;
23
30
  breakTolerancePct?: number;
24
31
  entryProximityPct?: number;
32
+ entryProximityMode?: EntryProximityMode;
33
+ entryProximityAtr?: number | null;
25
34
  };
26
35
  export type ResolvePatternLimitResult = {
27
36
  ok: true;
@@ -31,7 +40,7 @@ export type ResolvePatternLimitResult = {
31
40
  unclearReason: string;
32
41
  };
33
42
  export declare function patternPhase(lastClose: number, support: number, resistance: number, tolerancePct?: number): PatternPhase;
34
- export declare function withinEntryProximity(lastClose: number, entry: number, maxPct?: number): boolean;
43
+ export declare function withinEntryProximity(lastClose: number, entry: number, maxPct?: number, options?: WithinEntryProximityOptions): boolean;
35
44
  export declare function boundaryAtRightEdge(levels: PatternKeyLevelSummary[]): {
36
45
  support: number;
37
46
  resistance: number;
@@ -1 +1 @@
1
- {"version":3,"file":"pattern-limit-entry.d.ts","sourceRoot":"","sources":["../../../../../src/core/chart/analysis/trade-setups/pattern-limit-entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,iDAAiD,CAAC;AAC5F,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,GAAG,sBAAsB,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,cAAc,GAAG,cAAc,CAAC;AAEtE,MAAM,MAAM,kBAAkB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,iBAAiB,CAAC;IAC9B,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACtC,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,sBAAsB,EAAE,CAAC;IACpC,kBAAkB,EAAE,cAAc,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAClC;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAC,GACtC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAC,CAAC;AAMtC,wBAAgB,YAAY,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,YAAY,SAA8B,GACxC,YAAY,CAYd;AAED,wBAAgB,oBAAoB,CACnC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,SAA8B,GAClC,OAAO,CAKT;AA4CD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,sBAAsB,EAAE,GAAG;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACxB,GAAG,IAAI,CA+BP;AAqID,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,wBAAwB,GAAG,yBAAyB,CA0XpG"}
1
+ {"version":3,"file":"pattern-limit-entry.d.ts","sourceRoot":"","sources":["../../../../../src/core/chart/analysis/trade-setups/pattern-limit-entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,iDAAiD,CAAC;AAC5F,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAC7C,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,KAAK,CAAC;AACjD,eAAO,MAAM,4BAA4B,EAAE,kBAA4B,CAAC;AAExE,MAAM,MAAM,2BAA2B,GAAG;IACzC,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB,CAAC;AAEF,wBAAgB,uBAAuB,CACtC,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,kBAAiD,GACrD,MAAM,CAER;AAED,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,GAAG,sBAAsB,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,cAAc,GAAG,cAAc,CAAC;AAEtE,MAAM,MAAM,kBAAkB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,iBAAiB,CAAC;IAC9B,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACtC,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,sBAAsB,EAAE,CAAC;IACpC,kBAAkB,EAAE,cAAc,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAClC;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAC,GACtC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAC,CAAC;AAMtC,wBAAgB,YAAY,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,YAAY,SAA8B,GACxC,YAAY,CAYd;AAED,wBAAgB,oBAAoB,CACnC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,SAA8B,EACpC,OAAO,CAAC,EAAE,2BAA2B,GACnC,OAAO,CAiBT;AA6DD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,sBAAsB,EAAE,GAAG;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACxB,GAAG,IAAI,CA+BP;AAqJD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,wBAAwB,GAAG,yBAAyB,CAqcpG"}
@@ -1,5 +1,9 @@
1
1
  export const DEFAULT_BREAK_TOLERANCE_PCT = 0.1;
2
2
  export const DEFAULT_ENTRY_PROXIMITY_PCT = 1;
3
+ export const DEFAULT_ENTRY_PROXIMITY_MODE = 'price';
4
+ export function entryProximityGateLabel(pct, mode = DEFAULT_ENTRY_PROXIMITY_MODE) {
5
+ return mode === 'atr' ? `${pct}% of ATR` : `${pct}% of entry`;
6
+ }
3
7
  function tolPrice(price, pct) {
4
8
  return Math.abs(price) * (pct / 100);
5
9
  }
@@ -16,11 +20,33 @@ export function patternPhase(lastClose, support, resistance, tolerancePct = DEFA
16
20
  }
17
21
  return 'inside';
18
22
  }
19
- export function withinEntryProximity(lastClose, entry, maxPct = DEFAULT_ENTRY_PROXIMITY_PCT) {
20
- if (!Number.isFinite(lastClose) || !Number.isFinite(entry) || entry === 0) {
23
+ export function withinEntryProximity(lastClose, entry, maxPct = DEFAULT_ENTRY_PROXIMITY_PCT, options) {
24
+ if (!Number.isFinite(lastClose) || !Number.isFinite(entry)) {
25
+ return false;
26
+ }
27
+ const distance = Math.abs(lastClose - entry);
28
+ const mode = options?.mode ?? DEFAULT_ENTRY_PROXIMITY_MODE;
29
+ if (mode === 'atr') {
30
+ const atr = options?.atr;
31
+ if (atr == null || !Number.isFinite(atr) || atr <= 0) {
32
+ return false;
33
+ }
34
+ return distance <= (atr * maxPct) / 100;
35
+ }
36
+ if (entry === 0) {
21
37
  return false;
22
38
  }
23
- return (Math.abs(lastClose - entry) / Math.abs(entry)) * 100 <= maxPct;
39
+ return (distance / Math.abs(entry)) * 100 <= maxPct;
40
+ }
41
+ function failUnlessWithinEntryProximity(lastClose, entryPrice, pct, label, options) {
42
+ if (withinEntryProximity(lastClose, entryPrice, pct, options)) {
43
+ return null;
44
+ }
45
+ const mode = options?.mode ?? DEFAULT_ENTRY_PROXIMITY_MODE;
46
+ return {
47
+ ok: false,
48
+ unclearReason: `Price not within ${entryProximityGateLabel(pct, mode)} of ${label}.`,
49
+ };
24
50
  }
25
51
  function levelByLabels(levels, labels) {
26
52
  for (const want of labels) {
@@ -135,7 +161,7 @@ function okLevels(trigger, invalidation, entryPhase, entryOffsetMode, limitSide)
135
161
  },
136
162
  };
137
163
  }
138
- function boundaryLong(support, resistance, phase, proximityPct, lastClose, requireBreakoutOnly) {
164
+ function boundaryLong(support, resistance, phase, proximityPct, proximityOptions, lastClose, requireBreakoutOnly) {
139
165
  if (requireBreakoutOnly) {
140
166
  if (phase === 'inside') {
141
167
  return { ok: false, unclearReason: 'Price still inside pattern — no trade until breakout.' };
@@ -154,12 +180,13 @@ function boundaryLong(support, resistance, phase, proximityPct, lastClose, requi
154
180
  }
155
181
  const entry = { price: support.price, label: `${support.label} bounce` };
156
182
  const inv = { price: support.price, label: `${support.label} pattern fail` };
157
- if (!withinEntryProximity(lastClose, entry.price, proximityPct)) {
158
- return { ok: false, unclearReason: `Price not within ${proximityPct}% of support entry.` };
183
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, proximityPct, 'support entry', proximityOptions);
184
+ if (proximityFail) {
185
+ return proximityFail;
159
186
  }
160
187
  return okLevels(entry, inv, 'inside_pattern', 'bounce', 'long');
161
188
  }
162
- function boundaryShort(support, resistance, phase, proximityPct, lastClose, requireBreakoutOnly) {
189
+ function boundaryShort(support, resistance, phase, proximityPct, proximityOptions, lastClose, requireBreakoutOnly) {
163
190
  if (requireBreakoutOnly) {
164
191
  if (phase === 'inside') {
165
192
  return { ok: false, unclearReason: 'Price still inside pattern — no trade until breakout.' };
@@ -178,13 +205,18 @@ function boundaryShort(support, resistance, phase, proximityPct, lastClose, requ
178
205
  }
179
206
  const entry = { price: resistance.price, label: `${resistance.label} bounce` };
180
207
  const inv = { price: resistance.price, label: `${resistance.label} pattern fail` };
181
- if (!withinEntryProximity(lastClose, entry.price, proximityPct)) {
182
- return { ok: false, unclearReason: `Price not within ${proximityPct}% of resistance entry.` };
208
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, proximityPct, 'resistance entry', proximityOptions);
209
+ if (proximityFail) {
210
+ return proximityFail;
183
211
  }
184
212
  return okLevels(entry, inv, 'inside_pattern', 'bounce', 'short');
185
213
  }
186
214
  export function resolvePatternLimitLevels(input) {
187
- const { patternId, lastClose, keyLevels, breakTolerancePct = DEFAULT_BREAK_TOLERANCE_PCT, entryProximityPct = DEFAULT_ENTRY_PROXIMITY_PCT, } = input;
215
+ const { patternId, lastClose, keyLevels, breakTolerancePct = DEFAULT_BREAK_TOLERANCE_PCT, entryProximityPct = DEFAULT_ENTRY_PROXIMITY_PCT, entryProximityMode, entryProximityAtr, } = input;
216
+ const proximityOptions = {
217
+ mode: entryProximityMode,
218
+ atr: entryProximityAtr,
219
+ };
188
220
  const bounds = boundaryAtRightEdge(keyLevels);
189
221
  const phase = bounds != null
190
222
  ? patternPhase(lastClose, bounds.support, bounds.resistance, breakTolerancePct)
@@ -194,23 +226,23 @@ export function resolvePatternLimitLevels(input) {
194
226
  if (!bounds) {
195
227
  return { ok: false, unclearReason: 'Missing wedge boundary levels.' };
196
228
  }
197
- return boundaryLong({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, lastClose, false);
229
+ return boundaryLong({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, proximityOptions, lastClose, false);
198
230
  }
199
231
  case 'rising_wedge': {
200
232
  if (!bounds) {
201
233
  return { ok: false, unclearReason: 'Missing wedge boundary levels.' };
202
234
  }
203
- return boundaryShort({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, lastClose, false);
235
+ return boundaryShort({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, proximityOptions, lastClose, false);
204
236
  }
205
237
  case 'symmetrical_triangle': {
206
238
  if (!bounds) {
207
239
  return { ok: false, unclearReason: 'Missing triangle boundary levels.' };
208
240
  }
209
241
  if (phase === 'broken_above') {
210
- return boundaryLong({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, lastClose, true);
242
+ return boundaryLong({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, proximityOptions, lastClose, true);
211
243
  }
212
244
  if (phase === 'broken_below') {
213
- return boundaryShort({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, lastClose, true);
245
+ return boundaryShort({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, proximityOptions, lastClose, true);
214
246
  }
215
247
  return { ok: false, unclearReason: 'Symmetrical triangle — no trade until breakout.' };
216
248
  }
@@ -225,8 +257,9 @@ export function resolvePatternLimitLevels(input) {
225
257
  return okLevels({ price: res.price, label: `${res.label} retest` }, { price: sup.price, label: `${sup.label} pattern fail` }, 'post_breakout_retest', 'retest', 'long');
226
258
  }
227
259
  const entry = { price: sup.price, label: `${sup.label} bounce` };
228
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
229
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of support entry.` };
260
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'support entry', proximityOptions);
261
+ if (proximityFail) {
262
+ return proximityFail;
230
263
  }
231
264
  return okLevels(entry, { price: sup.price, label: `${sup.label} pattern fail` }, 'inside_pattern', 'bounce', 'long');
232
265
  }
@@ -241,8 +274,9 @@ export function resolvePatternLimitLevels(input) {
241
274
  return okLevels({ price: sup.price, label: `${sup.label} retest` }, { price: res.price, label: `${res.label} pattern fail` }, 'post_breakout_retest', 'retest', 'short');
242
275
  }
243
276
  const entry = { price: res.price, label: `${res.label} bounce` };
244
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
245
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of resistance entry.` };
277
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'resistance entry', proximityOptions);
278
+ if (proximityFail) {
279
+ return proximityFail;
246
280
  }
247
281
  return okLevels(entry, { price: res.price, label: `${res.label} pattern fail` }, 'inside_pattern', 'bounce', 'short');
248
282
  }
@@ -250,13 +284,13 @@ export function resolvePatternLimitLevels(input) {
250
284
  if (!bounds) {
251
285
  return { ok: false, unclearReason: 'Missing channel boundary levels.' };
252
286
  }
253
- return boundaryLong({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, lastClose, false);
287
+ return boundaryLong({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, proximityOptions, lastClose, false);
254
288
  }
255
289
  case 'channel_down': {
256
290
  if (!bounds) {
257
291
  return { ok: false, unclearReason: 'Missing channel boundary levels.' };
258
292
  }
259
- return boundaryShort({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, lastClose, false);
293
+ return boundaryShort({ price: bounds.support, label: bounds.supportLabel }, { price: bounds.resistance, label: bounds.resistanceLabel }, phase, entryProximityPct, proximityOptions, lastClose, false);
260
294
  }
261
295
  case 'double_bottom':
262
296
  case 'double_bottom_adam_eve': {
@@ -269,8 +303,9 @@ export function resolvePatternLimitLevels(input) {
269
303
  return okLevels({ price: neck.price, label: 'neckline retest' }, { price: trough.price, label: 'trough pattern fail' }, 'post_breakout_retest', 'retest', 'long');
270
304
  }
271
305
  const entry = { price: trough.price, label: 'trough bounce' };
272
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
273
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of trough entry.` };
306
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'trough entry', proximityOptions);
307
+ if (proximityFail) {
308
+ return proximityFail;
274
309
  }
275
310
  return okLevels(entry, { price: trough.price, label: 'trough pattern fail' }, 'inside_pattern', 'bounce', 'long');
276
311
  }
@@ -284,8 +319,9 @@ export function resolvePatternLimitLevels(input) {
284
319
  return okLevels({ price: neck.price, label: 'neckline retest' }, { price: peak.price, label: 'peak pattern fail' }, 'post_breakout_retest', 'retest', 'short');
285
320
  }
286
321
  const entry = { price: peak.price, label: 'peak bounce' };
287
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
288
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of peak entry.` };
322
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'peak entry', proximityOptions);
323
+ if (proximityFail) {
324
+ return proximityFail;
289
325
  }
290
326
  return okLevels(entry, { price: peak.price, label: 'peak pattern fail' }, 'inside_pattern', 'bounce', 'short');
291
327
  }
@@ -299,8 +335,9 @@ export function resolvePatternLimitLevels(input) {
299
335
  return okLevels({ price: neck.price, label: 'neckline retest' }, { price: head.price, label: 'head pattern fail' }, 'post_breakout_retest', 'retest', 'long');
300
336
  }
301
337
  const entry = { price: head.price, label: 'head bounce' };
302
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
303
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of head entry.` };
338
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'head entry', proximityOptions);
339
+ if (proximityFail) {
340
+ return proximityFail;
304
341
  }
305
342
  return okLevels(entry, { price: head.price, label: 'head pattern fail' }, 'inside_pattern', 'bounce', 'long');
306
343
  }
@@ -314,8 +351,9 @@ export function resolvePatternLimitLevels(input) {
314
351
  return okLevels({ price: neck.price, label: 'neckline retest' }, { price: head.price, label: 'head pattern fail' }, 'post_breakout_retest', 'retest', 'short');
315
352
  }
316
353
  const entry = { price: head.price, label: 'head bounce' };
317
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
318
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of head entry.` };
354
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'head entry', proximityOptions);
355
+ if (proximityFail) {
356
+ return proximityFail;
319
357
  }
320
358
  return okLevels(entry, { price: head.price, label: 'head pattern fail' }, 'inside_pattern', 'bounce', 'short');
321
359
  }
@@ -331,8 +369,9 @@ export function resolvePatternLimitLevels(input) {
331
369
  return okLevels({ price: rim.price, label: 'rim retest' }, { price: invPrice, label: 'cup/handle pattern fail' }, 'post_breakout_retest', 'retest', 'long');
332
370
  }
333
371
  const entry = { price: (handle ?? cupLow).price, label: 'handle bounce' };
334
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
335
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of handle entry.` };
372
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'handle entry', proximityOptions);
373
+ if (proximityFail) {
374
+ return proximityFail;
336
375
  }
337
376
  return okLevels(entry, { price: invPrice, label: 'cup/handle pattern fail' }, 'inside_pattern', 'bounce', 'long');
338
377
  }
@@ -347,8 +386,9 @@ export function resolvePatternLimitLevels(input) {
347
386
  return okLevels({ price: high.price, label: 'flag upper retest' }, { price: low.price, label: 'flag low pattern fail' }, 'post_breakout_retest', 'retest', 'long');
348
387
  }
349
388
  const entry = { price: low.price, label: 'flag low bounce' };
350
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
351
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of flag support entry.` };
389
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'flag support entry', proximityOptions);
390
+ if (proximityFail) {
391
+ return proximityFail;
352
392
  }
353
393
  return okLevels(entry, { price: low.price, label: 'flag low pattern fail' }, 'inside_pattern', 'bounce', 'long');
354
394
  }
@@ -363,8 +403,9 @@ export function resolvePatternLimitLevels(input) {
363
403
  return okLevels({ price: low.price, label: 'flag lower retest' }, { price: high.price, label: 'flag high pattern fail' }, 'post_breakout_retest', 'retest', 'short');
364
404
  }
365
405
  const entry = { price: high.price, label: 'flag upper bounce' };
366
- if (!withinEntryProximity(lastClose, entry.price, entryProximityPct)) {
367
- return { ok: false, unclearReason: `Price not within ${entryProximityPct}% of flag resistance entry.` };
406
+ const proximityFail = failUnlessWithinEntryProximity(lastClose, entry.price, entryProximityPct, 'flag resistance entry', proximityOptions);
407
+ if (proximityFail) {
408
+ return proximityFail;
368
409
  }
369
410
  return okLevels(entry, { price: high.price, label: 'flag high pattern fail' }, 'inside_pattern', 'bounce', 'short');
370
411
  }