@aetherwealth/sdk 0.1.32

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.
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Opt-in Zod parsers for aether-backend response shapes (camelCase). Compile-
3
+ * time safety comes from `types.ts`; import these only when you want runtime
4
+ * validation of untrusted responses:
5
+ *
6
+ * ```ts
7
+ * import {parseTrade} from '@aetherwealth/sdk'
8
+ * const trade = parseTrade(await client.trades.get(id))
9
+ * ```
10
+ *
11
+ * Schemas mirror the backend Zod schemas (the source of truth) and are
12
+ * `.passthrough()`-tolerant so a backend that adds a field doesn't break
13
+ * older SDK consumers.
14
+ */
15
+ import { z } from 'zod';
16
+ export declare const tradeDirectionSchema: z.ZodEnum<{
17
+ LONG: "LONG";
18
+ SHORT: "SHORT";
19
+ }>;
20
+ export declare const tradeStatusSchema: z.ZodEnum<{
21
+ OPEN: "OPEN";
22
+ CLOSED: "CLOSED";
23
+ CANCELLED: "CANCELLED";
24
+ }>;
25
+ export declare const tradeSchema: z.ZodObject<{
26
+ id: z.ZodString;
27
+ userId: z.ZodString;
28
+ accountId: z.ZodString;
29
+ pair: z.ZodString;
30
+ direction: z.ZodEnum<{
31
+ LONG: "LONG";
32
+ SHORT: "SHORT";
33
+ }>;
34
+ entryPrice: z.ZodNumber;
35
+ exitPrice: z.ZodNullable<z.ZodNumber>;
36
+ stopLoss: z.ZodNullable<z.ZodNumber>;
37
+ takeProfit: z.ZodNullable<z.ZodNumber>;
38
+ lotSize: z.ZodNumber;
39
+ entryTime: z.ZodString;
40
+ exitTime: z.ZodNullable<z.ZodString>;
41
+ status: z.ZodEnum<{
42
+ OPEN: "OPEN";
43
+ CLOSED: "CLOSED";
44
+ CANCELLED: "CANCELLED";
45
+ }>;
46
+ pnl: z.ZodNullable<z.ZodNumber>;
47
+ pnlPercent: z.ZodNullable<z.ZodNumber>;
48
+ pnlPips: z.ZodNullable<z.ZodNumber>;
49
+ fees: z.ZodNumber;
50
+ swap: z.ZodNumber;
51
+ notes: z.ZodNullable<z.ZodString>;
52
+ setupNotes: z.ZodNullable<z.ZodString>;
53
+ emotionalTag: z.ZodNullable<z.ZodString>;
54
+ timeframe: z.ZodNullable<z.ZodString>;
55
+ screenshotUrl: z.ZodNullable<z.ZodString>;
56
+ riskPercent: z.ZodNullable<z.ZodNumber>;
57
+ initialRisk: z.ZodNullable<z.ZodNumber>;
58
+ rMultiple: z.ZodNullable<z.ZodNumber>;
59
+ notesFormat: z.ZodNullable<z.ZodString>;
60
+ tags: z.ZodArray<z.ZodString>;
61
+ createdAt: z.ZodString;
62
+ updatedAt: z.ZodString;
63
+ }, z.core.$loose>;
64
+ export declare const accountSchema: z.ZodObject<{
65
+ id: z.ZodString;
66
+ userId: z.ZodString;
67
+ name: z.ZodString;
68
+ broker: z.ZodNullable<z.ZodString>;
69
+ accountType: z.ZodString;
70
+ initialBalance: z.ZodNumber;
71
+ currency: z.ZodString;
72
+ notes: z.ZodNullable<z.ZodString>;
73
+ isActive: z.ZodBoolean;
74
+ defaultRiskAmount: z.ZodNullable<z.ZodNumber>;
75
+ createdAt: z.ZodString;
76
+ updatedAt: z.ZodString;
77
+ }, z.core.$loose>;
78
+ export declare const tradingStatsSchema: z.ZodObject<{
79
+ totalTrades: z.ZodNumber;
80
+ winRate: z.ZodNumber;
81
+ profitFactor: z.ZodNumber;
82
+ totalPnl: z.ZodNumber;
83
+ totalPnlPips: z.ZodNumber;
84
+ avgWin: z.ZodNumber;
85
+ avgLoss: z.ZodNumber;
86
+ maxDrawdown: z.ZodNumber;
87
+ sharpeRatio: z.ZodNullable<z.ZodNumber>;
88
+ riskRewardAvg: z.ZodNullable<z.ZodNumber>;
89
+ bestPair: z.ZodNullable<z.ZodString>;
90
+ worstPair: z.ZodNullable<z.ZodString>;
91
+ avgHoldTimeMinutes: z.ZodNumber;
92
+ avgR: z.ZodNullable<z.ZodNumber>;
93
+ expectancyR: z.ZodNullable<z.ZodNumber>;
94
+ sqn: z.ZodNullable<z.ZodNumber>;
95
+ consecutiveWins: z.ZodNumber;
96
+ consecutiveLosses: z.ZodNumber;
97
+ }, z.core.$loose>;
98
+ export declare const priceConditionSchema: z.ZodEnum<{
99
+ above: "above";
100
+ below: "below";
101
+ crosses: "crosses";
102
+ }>;
103
+ export declare const triggerTypeSchema: z.ZodEnum<{
104
+ close: "close";
105
+ wick: "wick";
106
+ }>;
107
+ export declare const dedupModeSchema: z.ZodEnum<{
108
+ edge: "edge";
109
+ continuous: "continuous";
110
+ }>;
111
+ export declare const alertSchema: z.ZodObject<{
112
+ id: z.ZodString;
113
+ userId: z.ZodString;
114
+ pair: z.ZodString;
115
+ timeframe: z.ZodString;
116
+ alertType: z.ZodEnum<{
117
+ price: "price";
118
+ trendline: "trendline";
119
+ }>;
120
+ price: z.ZodNullable<z.ZodNumber>;
121
+ price1: z.ZodNullable<z.ZodNumber>;
122
+ time1: z.ZodNullable<z.ZodString>;
123
+ price2: z.ZodNullable<z.ZodNumber>;
124
+ time2: z.ZodNullable<z.ZodString>;
125
+ slope: z.ZodNullable<z.ZodNumber>;
126
+ intercept: z.ZodNullable<z.ZodNumber>;
127
+ condition: z.ZodNullable<z.ZodEnum<{
128
+ above: "above";
129
+ below: "below";
130
+ crosses: "crosses";
131
+ }>>;
132
+ triggerType: z.ZodEnum<{
133
+ close: "close";
134
+ wick: "wick";
135
+ }>;
136
+ isPersistent: z.ZodBoolean;
137
+ isActive: z.ZodBoolean;
138
+ isArchived: z.ZodBoolean;
139
+ notifyEmail: z.ZodBoolean;
140
+ notifyPush: z.ZodBoolean;
141
+ message: z.ZodNullable<z.ZodString>;
142
+ triggeredAt: z.ZodNullable<z.ZodString>;
143
+ triggeredPrice: z.ZodNullable<z.ZodNumber>;
144
+ triggerCount: z.ZodNumber;
145
+ expiresAt: z.ZodNullable<z.ZodString>;
146
+ createdAt: z.ZodString;
147
+ updatedAt: z.ZodString;
148
+ }, z.core.$loose>;
149
+ export declare const indicatorConditionSchema: z.ZodUnion<readonly [z.ZodObject<{
150
+ op: z.ZodEnum<{
151
+ gt: "gt";
152
+ gte: "gte";
153
+ lt: "lt";
154
+ lte: "lte";
155
+ eq: "eq";
156
+ crosses_above: "crosses_above";
157
+ crosses_below: "crosses_below";
158
+ }>;
159
+ threshold: z.ZodNumber;
160
+ }, z.core.$strip>, z.ZodObject<{
161
+ op: z.ZodEnum<{
162
+ gt_series: "gt_series";
163
+ lt_series: "lt_series";
164
+ crosses_above_series: "crosses_above_series";
165
+ crosses_below_series: "crosses_below_series";
166
+ }>;
167
+ other: z.ZodString;
168
+ }, z.core.$strip>]>;
169
+ export declare const indicatorAlertSchema: z.ZodObject<{
170
+ id: z.ZodString;
171
+ userId: z.ZodString;
172
+ pair: z.ZodString;
173
+ timeframe: z.ZodString;
174
+ indicatorType: z.ZodString;
175
+ indicatorParams: z.ZodRecord<z.ZodString, z.ZodUnknown>;
176
+ customIndicatorId: z.ZodNullable<z.ZodString>;
177
+ customIndicatorVersion: z.ZodNullable<z.ZodNumber>;
178
+ outputSeries: z.ZodNullable<z.ZodString>;
179
+ condition: z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
180
+ op: z.ZodEnum<{
181
+ gt: "gt";
182
+ gte: "gte";
183
+ lt: "lt";
184
+ lte: "lte";
185
+ eq: "eq";
186
+ crosses_above: "crosses_above";
187
+ crosses_below: "crosses_below";
188
+ }>;
189
+ threshold: z.ZodNumber;
190
+ }, z.core.$strip>, z.ZodObject<{
191
+ op: z.ZodEnum<{
192
+ gt_series: "gt_series";
193
+ lt_series: "lt_series";
194
+ crosses_above_series: "crosses_above_series";
195
+ crosses_below_series: "crosses_below_series";
196
+ }>;
197
+ other: z.ZodString;
198
+ }, z.core.$strip>]>>;
199
+ triggerType: z.ZodEnum<{
200
+ close: "close";
201
+ wick: "wick";
202
+ }>;
203
+ dedupMode: z.ZodEnum<{
204
+ edge: "edge";
205
+ continuous: "continuous";
206
+ }>;
207
+ isActive: z.ZodBoolean;
208
+ isArchived: z.ZodBoolean;
209
+ isTriggered: z.ZodBoolean;
210
+ isPersistent: z.ZodBoolean;
211
+ notifyEmail: z.ZodBoolean;
212
+ notifyPush: z.ZodBoolean;
213
+ message: z.ZodNullable<z.ZodString>;
214
+ triggeredAt: z.ZodNullable<z.ZodString>;
215
+ triggeredPrice: z.ZodNullable<z.ZodNumber>;
216
+ triggerCount: z.ZodNumber;
217
+ lastConditionState: z.ZodNullable<z.ZodString>;
218
+ lastTriggeredValue: z.ZodNullable<z.ZodNumber>;
219
+ lastEvaluatedAt: z.ZodNullable<z.ZodString>;
220
+ lastError: z.ZodNullable<z.ZodString>;
221
+ expiresAt: z.ZodNullable<z.ZodString>;
222
+ createdAt: z.ZodString;
223
+ updatedAt: z.ZodString;
224
+ }, z.core.$loose>;
225
+ export declare const diaryEntrySchema: z.ZodObject<{
226
+ id: z.ZodString;
227
+ date: z.ZodString;
228
+ content: z.ZodString;
229
+ mood: z.ZodNullable<z.ZodString>;
230
+ rating: z.ZodNullable<z.ZodNumber>;
231
+ tags: z.ZodArray<z.ZodString>;
232
+ createdAt: z.ZodString;
233
+ updatedAt: z.ZodString;
234
+ }, z.core.$loose>;
235
+ export declare const economicEventSchema: z.ZodObject<{
236
+ id: z.ZodString;
237
+ currency: z.ZodString;
238
+ release: z.ZodString;
239
+ eventName: z.ZodString;
240
+ announcementUnix: z.ZodNumber;
241
+ impact: z.ZodNumber;
242
+ actual: z.ZodNullable<z.ZodNumber>;
243
+ forecast: z.ZodNullable<z.ZodNumber>;
244
+ previous: z.ZodNullable<z.ZodNumber>;
245
+ }, z.core.$loose>;
246
+ export declare const marketConfigSchema: z.ZodObject<{
247
+ supportedTAPairs: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>;
248
+ supportedFAPairs: z.ZodRecord<z.ZodString, z.ZodUnknown>;
249
+ supportedTimeframes: z.ZodArray<z.ZodString>;
250
+ supportedFACurrencies: z.ZodArray<z.ZodString>;
251
+ }, z.core.$loose>;
252
+ export declare const macroSeriesPointSchema: z.ZodObject<{
253
+ date: z.ZodString;
254
+ val: z.ZodNumber;
255
+ announcement_datetime: z.ZodNumber;
256
+ }, z.core.$loose>;
257
+ export declare const macroSeriesResultSchema: z.ZodObject<{
258
+ currency: z.ZodString;
259
+ indicator: z.ZodString;
260
+ unit: z.ZodOptional<z.ZodString>;
261
+ frequency: z.ZodOptional<z.ZodString>;
262
+ has_official_forecast: z.ZodOptional<z.ZodBoolean>;
263
+ series: z.ZodArray<z.ZodObject<{
264
+ date: z.ZodString;
265
+ val: z.ZodNumber;
266
+ announcement_datetime: z.ZodNumber;
267
+ }, z.core.$loose>>;
268
+ cb_target: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
269
+ cachedAt: z.ZodOptional<z.ZodNumber>;
270
+ }, z.core.$loose>;
271
+ export declare const paginationSchema: z.ZodObject<{
272
+ page: z.ZodNumber;
273
+ limit: z.ZodNumber;
274
+ total: z.ZodNumber;
275
+ totalPages: z.ZodNumber;
276
+ }, z.core.$strip>;
277
+ export declare const parseTrade: (value: unknown) => z.infer<typeof tradeSchema>;
278
+ export declare const parseAccount: (value: unknown) => z.infer<typeof accountSchema>;
279
+ export declare const parseTradingStats: (value: unknown) => z.infer<typeof tradingStatsSchema>;
280
+ export declare const parseAlert: (value: unknown) => z.infer<typeof alertSchema>;
281
+ export declare const parseIndicatorAlert: (value: unknown) => z.infer<typeof indicatorAlertSchema>;
282
+ export declare const parseDiaryEntry: (value: unknown) => z.infer<typeof diaryEntrySchema>;
283
+ export declare const parseEconomicEvent: (value: unknown) => z.infer<typeof economicEventSchema>;
284
+ export declare const parseMarketConfig: (value: unknown) => z.infer<typeof marketConfigSchema>;
285
+ /** `market.macro` resolves `null` when the backend has no series — pass it through. */
286
+ export declare const parseMacroSeriesResult: (value: unknown) => z.infer<typeof macroSeriesResultSchema> | null;
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Opt-in Zod parsers for aether-backend response shapes (camelCase). Compile-
3
+ * time safety comes from `types.ts`; import these only when you want runtime
4
+ * validation of untrusted responses:
5
+ *
6
+ * ```ts
7
+ * import {parseTrade} from '@aetherwealth/sdk'
8
+ * const trade = parseTrade(await client.trades.get(id))
9
+ * ```
10
+ *
11
+ * Schemas mirror the backend Zod schemas (the source of truth) and are
12
+ * `.passthrough()`-tolerant so a backend that adds a field doesn't break
13
+ * older SDK consumers.
14
+ */
15
+ import { z } from 'zod';
16
+ export const tradeDirectionSchema = z.enum(['LONG', 'SHORT']);
17
+ export const tradeStatusSchema = z.enum(['OPEN', 'CLOSED', 'CANCELLED']);
18
+ export const tradeSchema = z
19
+ .object({
20
+ id: z.string(),
21
+ userId: z.string(),
22
+ accountId: z.string(),
23
+ pair: z.string(),
24
+ direction: tradeDirectionSchema,
25
+ entryPrice: z.number(),
26
+ exitPrice: z.number().nullable(),
27
+ stopLoss: z.number().nullable(),
28
+ takeProfit: z.number().nullable(),
29
+ lotSize: z.number(),
30
+ entryTime: z.string(),
31
+ exitTime: z.string().nullable(),
32
+ status: tradeStatusSchema,
33
+ pnl: z.number().nullable(),
34
+ pnlPercent: z.number().nullable(),
35
+ pnlPips: z.number().nullable(),
36
+ fees: z.number(),
37
+ swap: z.number(),
38
+ notes: z.string().nullable(),
39
+ setupNotes: z.string().nullable(),
40
+ emotionalTag: z.string().nullable(),
41
+ timeframe: z.string().nullable(),
42
+ screenshotUrl: z.string().nullable(),
43
+ riskPercent: z.number().nullable(),
44
+ initialRisk: z.number().nullable(),
45
+ rMultiple: z.number().nullable(),
46
+ notesFormat: z.string().nullable(),
47
+ tags: z.array(z.string()),
48
+ createdAt: z.string(),
49
+ updatedAt: z.string()
50
+ })
51
+ .passthrough();
52
+ export const accountSchema = z
53
+ .object({
54
+ id: z.string(),
55
+ userId: z.string(),
56
+ name: z.string(),
57
+ broker: z.string().nullable(),
58
+ accountType: z.string(),
59
+ initialBalance: z.number(),
60
+ currency: z.string(),
61
+ notes: z.string().nullable(),
62
+ isActive: z.boolean(),
63
+ defaultRiskAmount: z.number().nullable(),
64
+ createdAt: z.string(),
65
+ updatedAt: z.string()
66
+ })
67
+ .passthrough();
68
+ export const tradingStatsSchema = z
69
+ .object({
70
+ totalTrades: z.number(),
71
+ winRate: z.number(),
72
+ profitFactor: z.number(),
73
+ totalPnl: z.number(),
74
+ totalPnlPips: z.number(),
75
+ avgWin: z.number(),
76
+ avgLoss: z.number(),
77
+ maxDrawdown: z.number(),
78
+ sharpeRatio: z.number().nullable(),
79
+ riskRewardAvg: z.number().nullable(),
80
+ bestPair: z.string().nullable(),
81
+ worstPair: z.string().nullable(),
82
+ avgHoldTimeMinutes: z.number(),
83
+ avgR: z.number().nullable(),
84
+ expectancyR: z.number().nullable(),
85
+ sqn: z.number().nullable(),
86
+ consecutiveWins: z.number(),
87
+ consecutiveLosses: z.number()
88
+ })
89
+ .passthrough();
90
+ export const priceConditionSchema = z.enum(['above', 'below', 'crosses']);
91
+ export const triggerTypeSchema = z.enum(['close', 'wick']);
92
+ export const dedupModeSchema = z.enum(['edge', 'continuous']);
93
+ export const alertSchema = z
94
+ .object({
95
+ id: z.string(),
96
+ userId: z.string(),
97
+ pair: z.string(),
98
+ timeframe: z.string(),
99
+ alertType: z.enum(['price', 'trendline']),
100
+ price: z.number().nullable(),
101
+ price1: z.number().nullable(),
102
+ time1: z.string().nullable(),
103
+ price2: z.number().nullable(),
104
+ time2: z.string().nullable(),
105
+ slope: z.number().nullable(),
106
+ intercept: z.number().nullable(),
107
+ condition: priceConditionSchema.nullable(),
108
+ triggerType: triggerTypeSchema,
109
+ isPersistent: z.boolean(),
110
+ isActive: z.boolean(),
111
+ isArchived: z.boolean(),
112
+ notifyEmail: z.boolean(),
113
+ notifyPush: z.boolean(),
114
+ message: z.string().nullable(),
115
+ triggeredAt: z.string().nullable(),
116
+ triggeredPrice: z.number().nullable(),
117
+ triggerCount: z.number().int(),
118
+ expiresAt: z.string().nullable(),
119
+ createdAt: z.string(),
120
+ updatedAt: z.string()
121
+ })
122
+ .passthrough();
123
+ export const indicatorConditionSchema = z.union([
124
+ z.object({
125
+ op: z.enum(['gt', 'gte', 'lt', 'lte', 'eq', 'crosses_above', 'crosses_below']),
126
+ threshold: z.number()
127
+ }),
128
+ z.object({
129
+ op: z.enum(['gt_series', 'lt_series', 'crosses_above_series', 'crosses_below_series']),
130
+ other: z.string()
131
+ })
132
+ ]);
133
+ export const indicatorAlertSchema = z
134
+ .object({
135
+ id: z.string(),
136
+ userId: z.string(),
137
+ pair: z.string(),
138
+ timeframe: z.string(),
139
+ indicatorType: z.string(),
140
+ indicatorParams: z.record(z.string(), z.unknown()),
141
+ customIndicatorId: z.string().nullable(),
142
+ customIndicatorVersion: z.number().nullable(),
143
+ outputSeries: z.string().nullable(),
144
+ condition: indicatorConditionSchema.nullable(),
145
+ triggerType: triggerTypeSchema,
146
+ dedupMode: dedupModeSchema,
147
+ isActive: z.boolean(),
148
+ isArchived: z.boolean(),
149
+ isTriggered: z.boolean(),
150
+ isPersistent: z.boolean(),
151
+ notifyEmail: z.boolean(),
152
+ notifyPush: z.boolean(),
153
+ message: z.string().nullable(),
154
+ triggeredAt: z.string().nullable(),
155
+ triggeredPrice: z.number().nullable(),
156
+ triggerCount: z.number().int(),
157
+ lastConditionState: z.string().nullable(),
158
+ lastTriggeredValue: z.number().nullable(),
159
+ lastEvaluatedAt: z.string().nullable(),
160
+ lastError: z.string().nullable(),
161
+ expiresAt: z.string().nullable(),
162
+ createdAt: z.string(),
163
+ updatedAt: z.string()
164
+ })
165
+ .passthrough();
166
+ export const diaryEntrySchema = z
167
+ .object({
168
+ id: z.string(),
169
+ date: z.string(),
170
+ content: z.string(),
171
+ mood: z.string().nullable(),
172
+ rating: z.number().nullable(),
173
+ tags: z.array(z.string()),
174
+ createdAt: z.string(),
175
+ updatedAt: z.string()
176
+ })
177
+ .passthrough();
178
+ export const economicEventSchema = z
179
+ .object({
180
+ id: z.string(),
181
+ currency: z.string(),
182
+ release: z.string(),
183
+ eventName: z.string(),
184
+ announcementUnix: z.number().int(),
185
+ impact: z.number().int(),
186
+ actual: z.number().nullable(),
187
+ forecast: z.number().nullable(),
188
+ previous: z.number().nullable()
189
+ })
190
+ .passthrough();
191
+ // Nested instrument-metadata keys stay snake_case (emitted literally by the
192
+ // backend), so the record values are opaque blobs.
193
+ export const marketConfigSchema = z
194
+ .object({
195
+ supportedTAPairs: z.record(z.string(), z.record(z.string(), z.unknown())),
196
+ supportedFAPairs: z.record(z.string(), z.unknown()),
197
+ supportedTimeframes: z.array(z.string()),
198
+ supportedFACurrencies: z.array(z.string())
199
+ })
200
+ .passthrough();
201
+ export const macroSeriesPointSchema = z
202
+ .object({
203
+ date: z.string(),
204
+ val: z.number(),
205
+ announcement_datetime: z.number()
206
+ })
207
+ .passthrough();
208
+ // fxmacrodata series forwarded untransformed — the snake_case fields match the
209
+ // `MacroSeriesResult` wire type. `market.macro` may resolve `null` (no series);
210
+ // the null case is handled by `parseMacroSeriesResult`, not the schema.
211
+ export const macroSeriesResultSchema = z
212
+ .object({
213
+ currency: z.string(),
214
+ indicator: z.string(),
215
+ unit: z.string().optional(),
216
+ frequency: z.string().optional(),
217
+ has_official_forecast: z.boolean().optional(),
218
+ series: z.array(macroSeriesPointSchema),
219
+ cb_target: z.record(z.string(), z.unknown()).optional(),
220
+ cachedAt: z.number().optional()
221
+ })
222
+ .passthrough();
223
+ export const paginationSchema = z.object({
224
+ page: z.number(),
225
+ limit: z.number(),
226
+ total: z.number(),
227
+ totalPages: z.number()
228
+ });
229
+ // ── Opt-in parse helpers ─────────────────────────────────────────────────
230
+ export const parseTrade = (value) => tradeSchema.parse(value);
231
+ export const parseAccount = (value) => accountSchema.parse(value);
232
+ export const parseTradingStats = (value) => tradingStatsSchema.parse(value);
233
+ export const parseAlert = (value) => alertSchema.parse(value);
234
+ export const parseIndicatorAlert = (value) => indicatorAlertSchema.parse(value);
235
+ export const parseDiaryEntry = (value) => diaryEntrySchema.parse(value);
236
+ export const parseEconomicEvent = (value) => economicEventSchema.parse(value);
237
+ export const parseMarketConfig = (value) => marketConfigSchema.parse(value);
238
+ /** `market.macro` resolves `null` when the backend has no series — pass it through. */
239
+ export const parseMacroSeriesResult = (value) => value === null ? null : macroSeriesResultSchema.parse(value);