hedgequantx 2.6.161 → 2.6.162

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 (42) hide show
  1. package/package.json +1 -1
  2. package/src/menus/ai-agent-connect.js +181 -0
  3. package/src/menus/ai-agent-models.js +219 -0
  4. package/src/menus/ai-agent-oauth.js +292 -0
  5. package/src/menus/ai-agent-ui.js +141 -0
  6. package/src/menus/ai-agent.js +88 -1489
  7. package/src/pages/algo/copy-engine.js +449 -0
  8. package/src/pages/algo/copy-trading.js +11 -543
  9. package/src/pages/algo/smart-logs-data.js +218 -0
  10. package/src/pages/algo/smart-logs.js +9 -214
  11. package/src/pages/algo/ui-constants.js +144 -0
  12. package/src/pages/algo/ui-summary.js +184 -0
  13. package/src/pages/algo/ui.js +42 -526
  14. package/src/pages/stats-calculations.js +191 -0
  15. package/src/pages/stats-ui.js +381 -0
  16. package/src/pages/stats.js +14 -507
  17. package/src/services/ai/client-analysis.js +194 -0
  18. package/src/services/ai/client-models.js +333 -0
  19. package/src/services/ai/client.js +6 -489
  20. package/src/services/ai/index.js +2 -257
  21. package/src/services/ai/proxy-install.js +249 -0
  22. package/src/services/ai/proxy-manager.js +29 -411
  23. package/src/services/ai/proxy-remote.js +161 -0
  24. package/src/services/ai/supervisor-optimize.js +215 -0
  25. package/src/services/ai/supervisor-sync.js +178 -0
  26. package/src/services/ai/supervisor.js +50 -515
  27. package/src/services/ai/validation.js +250 -0
  28. package/src/services/hqx-server-events.js +110 -0
  29. package/src/services/hqx-server-handlers.js +217 -0
  30. package/src/services/hqx-server-latency.js +136 -0
  31. package/src/services/hqx-server.js +51 -403
  32. package/src/services/position-constants.js +28 -0
  33. package/src/services/position-manager.js +105 -554
  34. package/src/services/position-momentum.js +206 -0
  35. package/src/services/projectx/accounts.js +142 -0
  36. package/src/services/projectx/index.js +40 -289
  37. package/src/services/projectx/trading.js +180 -0
  38. package/src/services/rithmic/handlers.js +2 -208
  39. package/src/services/rithmic/index.js +32 -542
  40. package/src/services/rithmic/latency-tracker.js +182 -0
  41. package/src/services/rithmic/specs.js +146 -0
  42. package/src/services/rithmic/trade-history.js +254 -0
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Smart Logs Message Pools and State
3
+ * @module pages/algo/smart-logs-data
4
+ *
5
+ * HF-grade message pools for institutional logging.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ // State tracking
11
+ const recentMessages = new Map();
12
+ const MAX_RECENT = 5;
13
+
14
+ // Market microstructure state
15
+ const microstructure = {
16
+ ofi: 0,
17
+ cumDelta: 0,
18
+ delta: 0,
19
+ zscore: 0,
20
+ momentum: 0,
21
+ acceleration: 0,
22
+ spread: 0,
23
+ bidDepth: 0,
24
+ askDepth: 0,
25
+ imbalance: 0,
26
+ vwap: 0,
27
+ poc: 0,
28
+ atr: 0,
29
+ tps: 0,
30
+ buyVol: 0,
31
+ sellVol: 0,
32
+ lastUpdate: Date.now(),
33
+ };
34
+
35
+ // Position state
36
+ const position = {
37
+ side: null,
38
+ symbol: '',
39
+ size: 0,
40
+ entryPrice: 0,
41
+ currentPrice: 0,
42
+ stopLoss: 0,
43
+ takeProfit: 0,
44
+ entryTime: 0,
45
+ unrealizedPnl: 0,
46
+ tickSize: 0.25,
47
+ tickValue: 12.50,
48
+ };
49
+
50
+ // Message pools - HF Grade
51
+ const FLOW_AGGRESSIVE_BUY = [
52
+ 'Aggressive lifting offers',
53
+ 'Heavy buy-side absorption',
54
+ 'Institutional accumulation',
55
+ 'Delta surge positive',
56
+ 'Bid stacking detected',
57
+ 'Buy programs sweeping',
58
+ ];
59
+
60
+ const FLOW_AGGRESSIVE_SELL = [
61
+ 'Aggressive hitting bids',
62
+ 'Heavy sell-side distribution',
63
+ 'Institutional liquidation',
64
+ 'Delta surge negative',
65
+ 'Offer stacking detected',
66
+ 'Sell programs sweeping',
67
+ ];
68
+
69
+ const FLOW_BALANCED = [
70
+ 'Two-sided flow equilibrium',
71
+ 'Balanced book rotation',
72
+ 'Fair value discovery',
73
+ 'Neutral order flow',
74
+ 'Market making zone',
75
+ ];
76
+
77
+ const MR_OVERBOUGHT = [
78
+ 'Extended above VWAP band',
79
+ 'Z-score overbought extreme',
80
+ 'Mean reversion fade setup',
81
+ 'Exhaustion at upper band',
82
+ 'Stretched deviation short',
83
+ ];
84
+
85
+ const MR_OVERSOLD = [
86
+ 'Extended below VWAP band',
87
+ 'Z-score oversold extreme',
88
+ 'Mean reversion bounce setup',
89
+ 'Capitulation at lower band',
90
+ 'Stretched deviation long',
91
+ ];
92
+
93
+ const MOM_ACCELERATING_UP = [
94
+ 'Momentum acceleration +',
95
+ 'Velocity vector bullish',
96
+ 'Trend thrust positive',
97
+ 'Breakout momentum confirmed',
98
+ 'Impulse wave up',
99
+ ];
100
+
101
+ const MOM_ACCELERATING_DOWN = [
102
+ 'Momentum acceleration -',
103
+ 'Velocity vector bearish',
104
+ 'Trend thrust negative',
105
+ 'Breakdown momentum confirmed',
106
+ 'Impulse wave down',
107
+ ];
108
+
109
+ const VOL_EXPANSION = [
110
+ 'Volatility expansion cycle',
111
+ 'ATR breakout detected',
112
+ 'Range expansion phase',
113
+ 'Vol regime shift high',
114
+ 'Gamma event potential',
115
+ ];
116
+
117
+ const VOL_COMPRESSION = [
118
+ 'Volatility compression cycle',
119
+ 'ATR contraction detected',
120
+ 'Range compression phase',
121
+ 'Vol regime shift low',
122
+ 'Coiling for breakout',
123
+ ];
124
+
125
+ const POS_PROFIT_RUNNING = [
126
+ 'P&L positive running',
127
+ 'Trade thesis confirmed',
128
+ 'Alpha capture in progress',
129
+ 'Edge realization phase',
130
+ 'Position working target',
131
+ ];
132
+
133
+ const POS_LOSS_MANAGING = [
134
+ 'Adverse excursion mgmt',
135
+ 'Drawdown within params',
136
+ 'Risk budget consuming',
137
+ 'Position under pressure',
138
+ 'Defending stop level',
139
+ ];
140
+
141
+ const POS_NEAR_TARGET = [
142
+ 'Approaching profit target',
143
+ 'Near TP execution zone',
144
+ 'Exit liquidity scanning',
145
+ 'Target strike imminent',
146
+ 'Profit capture pending',
147
+ ];
148
+
149
+ const POS_NEAR_STOP = [
150
+ 'Near stop execution zone',
151
+ 'SL liquidity scanning',
152
+ 'Risk threshold proximity',
153
+ 'Stop strike imminent',
154
+ 'Loss containment pending',
155
+ ];
156
+
157
+ const SCANNING_ACTIVE = [
158
+ 'Scanning microstructure',
159
+ 'Analyzing order book',
160
+ 'Evaluating flow signals',
161
+ 'Pattern recognition active',
162
+ 'Setup detection running',
163
+ ];
164
+
165
+ // Helper functions
166
+ function getVariedMessage(category, pool, defaultMsg) {
167
+ const recent = recentMessages.get(category) || [];
168
+ const available = pool.filter(msg => !recent.includes(msg));
169
+ if (available.length === 0) {
170
+ recentMessages.set(category, []);
171
+ return pool[Math.floor(Math.random() * pool.length)] || defaultMsg;
172
+ }
173
+ const chosen = available[Math.floor(Math.random() * available.length)] || defaultMsg;
174
+ recent.push(chosen);
175
+ if (recent.length > MAX_RECENT) recent.shift();
176
+ recentMessages.set(category, recent);
177
+ return chosen;
178
+ }
179
+
180
+ function formatNumber(n, decimals = 2) {
181
+ if (n === undefined || n === null || isNaN(n)) return '--';
182
+ const num = parseFloat(n);
183
+ const sign = num >= 0 ? '+' : '';
184
+ return sign + num.toFixed(decimals);
185
+ }
186
+
187
+ function formatPnl(pnl) {
188
+ if (pnl === undefined || pnl === null) return '--';
189
+ return pnl >= 0 ? `+$${pnl.toFixed(2)}` : `-$${Math.abs(pnl).toFixed(2)}`;
190
+ }
191
+
192
+ module.exports = {
193
+ // State
194
+ microstructure,
195
+ position,
196
+ recentMessages,
197
+
198
+ // Pools
199
+ FLOW_AGGRESSIVE_BUY,
200
+ FLOW_AGGRESSIVE_SELL,
201
+ FLOW_BALANCED,
202
+ MR_OVERBOUGHT,
203
+ MR_OVERSOLD,
204
+ MOM_ACCELERATING_UP,
205
+ MOM_ACCELERATING_DOWN,
206
+ VOL_EXPANSION,
207
+ VOL_COMPRESSION,
208
+ POS_PROFIT_RUNNING,
209
+ POS_LOSS_MANAGING,
210
+ POS_NEAR_TARGET,
211
+ POS_NEAR_STOP,
212
+ SCANNING_ACTIVE,
213
+
214
+ // Helpers
215
+ getVariedMessage,
216
+ formatNumber,
217
+ formatPnl,
218
+ };
@@ -1,222 +1,17 @@
1
1
  /**
2
- * =============================================================================
3
- * HQX INSTITUTIONAL SMART LOGGING SYSTEM
4
- * =============================================================================
5
- * HedgeFund-grade execution logs with full market microstructure context
6
- *
7
- * SHOWS:
8
- * - Order Flow Imbalance (OFI) with directional bias
9
- * - Cumulative Delta & Volume Profile
10
- * - Z-Score deviation from fair value
11
- * - Momentum vectors & acceleration
12
- * - Liquidity depth & spread dynamics
13
- * - Position Greeks: Ticks to SL/TP, R-multiple, hold time
14
- * - Flow alignment score (position vs market flow)
15
- * - Tick-by-tick execution latency
2
+ * HQX Institutional Smart Logging System
3
+ * HedgeFund-grade execution logs with market microstructure context
16
4
  */
17
5
 
18
6
  'use strict';
19
7
 
20
- // =============================================================================
21
- // STATE TRACKING
22
- // =============================================================================
23
-
24
- const recentMessages = new Map();
25
- const MAX_RECENT = 5;
26
-
27
- // Market microstructure state
28
- const microstructure = {
29
- ofi: 0, // Order Flow Imbalance (-1 to +1)
30
- cumDelta: 0, // Cumulative Delta
31
- delta: 0, // Current bar delta
32
- zscore: 0, // Z-Score from VWAP/mean
33
- momentum: 0, // Price momentum
34
- acceleration: 0, // Momentum change rate
35
- spread: 0, // Bid-ask spread in ticks
36
- bidDepth: 0, // Bid side liquidity
37
- askDepth: 0, // Ask side liquidity
38
- imbalance: 0, // Book imbalance ratio
39
- vwap: 0, // Volume Weighted Avg Price
40
- poc: 0, // Point of Control
41
- atr: 0, // Average True Range
42
- tps: 0, // Ticks per second
43
- buyVol: 0, // Buy volume
44
- sellVol: 0, // Sell volume
45
- lastUpdate: Date.now(),
46
- };
47
-
48
- // Position state for Greeks calculation
49
- const position = {
50
- side: null, // 'LONG' | 'SHORT'
51
- symbol: '',
52
- size: 0,
53
- entryPrice: 0,
54
- currentPrice: 0,
55
- stopLoss: 0,
56
- takeProfit: 0,
57
- entryTime: 0,
58
- unrealizedPnl: 0,
59
- tickSize: 0.25,
60
- tickValue: 12.50,
61
- };
62
-
63
- // =============================================================================
64
- // HELPER FUNCTIONS
65
- // =============================================================================
66
-
67
- function getVariedMessage(category, pool, defaultMsg) {
68
- const recent = recentMessages.get(category) || [];
69
- const available = pool.filter(msg => !recent.includes(msg));
70
- if (available.length === 0) {
71
- recentMessages.set(category, []);
72
- return pool[Math.floor(Math.random() * pool.length)] || defaultMsg;
73
- }
74
- const chosen = available[Math.floor(Math.random() * available.length)] || defaultMsg;
75
- recent.push(chosen);
76
- if (recent.length > MAX_RECENT) recent.shift();
77
- recentMessages.set(category, recent);
78
- return chosen;
79
- }
80
-
81
- function formatNumber(n, decimals = 2) {
82
- if (n === undefined || n === null || isNaN(n)) return '--';
83
- const num = parseFloat(n);
84
- const sign = num >= 0 ? '+' : '';
85
- return sign + num.toFixed(decimals);
86
- }
87
-
88
- function formatPnl(pnl) {
89
- if (pnl === undefined || pnl === null) return '--';
90
- return pnl >= 0 ? `+$${pnl.toFixed(2)}` : `-$${Math.abs(pnl).toFixed(2)}`;
91
- }
92
-
93
- // =============================================================================
94
- // INSTITUTIONAL MESSAGE POOLS
95
- // =============================================================================
96
-
97
- // Flow Analysis - HF Grade
98
- const FLOW_AGGRESSIVE_BUY = [
99
- 'Aggressive lifting offers',
100
- 'Heavy buy-side absorption',
101
- 'Institutional accumulation',
102
- 'Delta surge positive',
103
- 'Bid stacking detected',
104
- 'Buy programs sweeping',
105
- ];
106
-
107
- const FLOW_AGGRESSIVE_SELL = [
108
- 'Aggressive hitting bids',
109
- 'Heavy sell-side distribution',
110
- 'Institutional liquidation',
111
- 'Delta surge negative',
112
- 'Offer stacking detected',
113
- 'Sell programs sweeping',
114
- ];
115
-
116
- const FLOW_BALANCED = [
117
- 'Two-sided flow equilibrium',
118
- 'Balanced book rotation',
119
- 'Fair value discovery',
120
- 'Neutral order flow',
121
- 'Market making zone',
122
- ];
123
-
124
- // Mean Reversion - HF Grade
125
- const MR_OVERBOUGHT = [
126
- 'Extended above VWAP band',
127
- 'Z-score overbought extreme',
128
- 'Mean reversion fade setup',
129
- 'Exhaustion at upper band',
130
- 'Stretched deviation short',
131
- ];
132
-
133
- const MR_OVERSOLD = [
134
- 'Extended below VWAP band',
135
- 'Z-score oversold extreme',
136
- 'Mean reversion bounce setup',
137
- 'Capitulation at lower band',
138
- 'Stretched deviation long',
139
- ];
140
-
141
- // Momentum - HF Grade
142
- const MOM_ACCELERATING_UP = [
143
- 'Momentum acceleration +',
144
- 'Velocity vector bullish',
145
- 'Trend thrust positive',
146
- 'Breakout momentum confirmed',
147
- 'Impulse wave up',
148
- ];
149
-
150
- const MOM_ACCELERATING_DOWN = [
151
- 'Momentum acceleration -',
152
- 'Velocity vector bearish',
153
- 'Trend thrust negative',
154
- 'Breakdown momentum confirmed',
155
- 'Impulse wave down',
156
- ];
157
-
158
- // Volatility - HF Grade
159
- const VOL_EXPANSION = [
160
- 'Volatility expansion cycle',
161
- 'ATR breakout detected',
162
- 'Range expansion phase',
163
- 'Vol regime shift high',
164
- 'Gamma event potential',
165
- ];
166
-
167
- const VOL_COMPRESSION = [
168
- 'Volatility compression cycle',
169
- 'ATR contraction detected',
170
- 'Range compression phase',
171
- 'Vol regime shift low',
172
- 'Coiling for breakout',
173
- ];
174
-
175
- // Position Status - HF Grade
176
- const POS_PROFIT_RUNNING = [
177
- 'P&L positive running',
178
- 'Trade thesis confirmed',
179
- 'Alpha capture in progress',
180
- 'Edge realization phase',
181
- 'Position working target',
182
- ];
183
-
184
- const POS_LOSS_MANAGING = [
185
- 'Adverse excursion mgmt',
186
- 'Drawdown within params',
187
- 'Risk budget consuming',
188
- 'Position under pressure',
189
- 'Defending stop level',
190
- ];
191
-
192
- const POS_NEAR_TARGET = [
193
- 'Approaching profit target',
194
- 'Near TP execution zone',
195
- 'Exit liquidity scanning',
196
- 'Target strike imminent',
197
- 'Profit capture pending',
198
- ];
199
-
200
- const POS_NEAR_STOP = [
201
- 'Near stop execution zone',
202
- 'SL liquidity scanning',
203
- 'Risk threshold proximity',
204
- 'Stop strike imminent',
205
- 'Loss containment pending',
206
- ];
207
-
208
- // Scanning - HF Grade
209
- const SCANNING_ACTIVE = [
210
- 'Scanning microstructure',
211
- 'Analyzing order book',
212
- 'Evaluating flow signals',
213
- 'Pattern recognition active',
214
- 'Setup detection running',
215
- ];
216
-
217
- // =============================================================================
218
- // MAIN LOG GENERATORS - HF GRADE
219
- // =============================================================================
8
+ const {
9
+ microstructure, position, getVariedMessage, formatNumber, formatPnl,
10
+ FLOW_AGGRESSIVE_BUY, FLOW_AGGRESSIVE_SELL, FLOW_BALANCED,
11
+ MR_OVERBOUGHT, MR_OVERSOLD, MOM_ACCELERATING_UP, MOM_ACCELERATING_DOWN,
12
+ VOL_EXPANSION, VOL_COMPRESSION, POS_PROFIT_RUNNING, POS_LOSS_MANAGING,
13
+ POS_NEAR_TARGET, POS_NEAR_STOP, SCANNING_ACTIVE,
14
+ } = require('./smart-logs-data');
220
15
 
221
16
  /**
222
17
  * Update microstructure state from strategy model values
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @fileoverview Algo UI Constants and Helpers
3
+ * Box drawing, colors, icons, and utility functions
4
+ */
5
+
6
+ const chalk = require('chalk');
7
+
8
+ // Box drawing characters
9
+ const BOX = {
10
+ TOP: '\u2554', BOT: '\u255A', V: '\u2551', H: '\u2550',
11
+ TR: '\u2557', BR: '\u255D', ML: '\u2560', MR: '\u2563',
12
+ TM: '\u2564', BM: '\u2567', MM: '\u256A', VS: '\u2502'
13
+ };
14
+
15
+ // Spinner characters
16
+ const SPINNER = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'];
17
+
18
+ // Log type colors - HF grade BOLD (FIXED colors - no variation)
19
+ const LOG_COLORS = {
20
+ fill_buy: chalk.green,
21
+ fill_sell: chalk.red,
22
+ fill_win: chalk.green,
23
+ fill_loss: chalk.red,
24
+ win: chalk.green,
25
+ loss: chalk.red,
26
+ be: chalk.yellow,
27
+ entry: chalk.cyan,
28
+ filled: chalk.green,
29
+ connected: chalk.cyan,
30
+ ready: chalk.green,
31
+ error: chalk.red,
32
+ reject: chalk.red,
33
+ info: chalk.gray,
34
+ system: chalk.magenta,
35
+ signal: chalk.yellow,
36
+ trade: chalk.green,
37
+ warning: chalk.yellow,
38
+ success: chalk.green,
39
+ analysis: chalk.magenta
40
+ };
41
+
42
+ // Log type icons - Unicode icons (ALL 8 chars wide for alignment)
43
+ const LOG_ICONS = {
44
+ fill_buy: '⬆ BUY ',
45
+ fill_sell: '⬇ SELL ',
46
+ fill_win: '✔ WIN ',
47
+ fill_loss: '✘ LOSS ',
48
+ win: '✔ WIN ',
49
+ loss: '✘ LOSS ',
50
+ be: '★ BE ',
51
+ entry: '➡ ENTRY',
52
+ filled: '✔ FILL ',
53
+ connected: '✔ CONN ',
54
+ ready: '✔ READY',
55
+ error: '✘ ERROR',
56
+ reject: '✘ REJCT',
57
+ info: '➡ INFO ',
58
+ system: '★ SYSTM',
59
+ signal: '★ SIGNL',
60
+ trade: '✔ TRADE',
61
+ success: '✔ SUCCS',
62
+ warning: '⬅ WARNG',
63
+ analysis: '★ ANLYS'
64
+ };
65
+
66
+ /** Strip ANSI codes from string */
67
+ const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*m/g, '');
68
+
69
+ /** Colorize message: positive numbers=cyan, negative=red, symbols=yellow */
70
+ const colorizeMessage = (msg) => {
71
+ if (!msg) return '';
72
+ if (msg.includes('\x1B[')) return msg;
73
+
74
+ return msg
75
+ .replace(/\+\$[\d,]+\.?\d*/g, (m) => chalk.cyan.bold(m))
76
+ .replace(/-\$[\d,]+\.?\d*/g, (m) => chalk.red.bold(m))
77
+ .replace(/\+\d+\.?\d*/g, (m) => chalk.cyan(m))
78
+ .replace(/-\d+\.?\d*/g, (m) => chalk.red(m))
79
+ .replace(/\b(NQ|ES|MNQ|MES|RTY|M2K|YM|MYM|CL|GC|SI)[A-Z]\d\b/g, (m) => chalk.yellow.bold(m))
80
+ .replace(/\d+\.?\d*%/g, (m) => chalk.cyan(m))
81
+ .replace(/\b\d{4,5}\.\d{2}\b/g, (m) => chalk.white.bold(m));
82
+ };
83
+
84
+ /** Center text in width */
85
+ const center = (text, width) => {
86
+ const pad = Math.floor((width - text.length) / 2);
87
+ return ' '.repeat(pad) + text + ' '.repeat(width - pad - text.length);
88
+ };
89
+
90
+ /** Fit text to exact width (truncate or pad) */
91
+ const fitToWidth = (text, width) => {
92
+ const plain = stripAnsi(text);
93
+ if (plain.length > width) {
94
+ let count = 0, cut = 0;
95
+ for (let i = 0; i < text.length && count < width - 3; i++) {
96
+ if (text[i] === '\x1B') { while (i < text.length && text[i] !== 'm') i++; }
97
+ else { count++; cut = i + 1; }
98
+ }
99
+ return text.substring(0, cut) + '...';
100
+ }
101
+ return text + ' '.repeat(width - plain.length);
102
+ };
103
+
104
+ /** Build a labeled cell for grid - UPPERCASE BOLD style */
105
+ const buildCell = (label, value, color, width) => {
106
+ const upperLabel = label.toUpperCase();
107
+ const upperValue = String(value).toUpperCase();
108
+ const text = ` ${chalk.bold(upperLabel)}: ${color.bold(upperValue)}`;
109
+ const plain = ` ${upperLabel}: ${upperValue}`;
110
+ return { text, plain, padded: text + ' '.repeat(Math.max(0, width - plain.length)) };
111
+ };
112
+
113
+ /** Check market hours */
114
+ const checkMarketStatus = () => {
115
+ const now = new Date();
116
+ const utcDay = now.getUTCDay();
117
+ const utcHour = now.getUTCHours();
118
+ const isDST = now.getTimezoneOffset() < Math.max(
119
+ new Date(now.getFullYear(), 0, 1).getTimezoneOffset(),
120
+ new Date(now.getFullYear(), 6, 1).getTimezoneOffset()
121
+ );
122
+ const ctOffset = isDST ? 5 : 6;
123
+ const ctHour = (utcHour - ctOffset + 24) % 24;
124
+ const ctDay = utcHour < ctOffset ? (utcDay + 6) % 7 : utcDay;
125
+
126
+ if (ctDay === 6) return { isOpen: false, message: 'Market closed (Saturday)' };
127
+ if (ctDay === 0 && ctHour < 17) return { isOpen: false, message: 'Market opens Sunday 5:00 PM CT' };
128
+ if (ctDay === 5 && ctHour >= 16) return { isOpen: false, message: 'Market closed (Friday after 4PM CT)' };
129
+ if (ctHour === 16 && ctDay >= 1 && ctDay <= 4) return { isOpen: false, message: 'Daily maintenance' };
130
+ return { isOpen: true, message: 'Market OPEN' };
131
+ };
132
+
133
+ module.exports = {
134
+ BOX,
135
+ SPINNER,
136
+ LOG_COLORS,
137
+ LOG_ICONS,
138
+ stripAnsi,
139
+ colorizeMessage,
140
+ center,
141
+ fitToWidth,
142
+ buildCell,
143
+ checkMarketStatus,
144
+ };