tradeblocks-mcp 3.0.2 → 3.0.3
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/README.md +82 -68
- package/dist/{chunk-LDKTV7GW.js → chunk-27S67XW3.js} +24 -52
- package/dist/chunk-27S67XW3.js.map +1 -0
- package/dist/{chunk-FGZH632F.js → chunk-2E63THNI.js} +13 -11
- package/dist/chunk-2E63THNI.js.map +1 -0
- package/dist/{chunk-BKQ4PM4Y.js → chunk-6S37CXUA.js} +11 -13
- package/dist/chunk-6S37CXUA.js.map +1 -0
- package/dist/{chunk-PRAYH3RT.js → chunk-AP7IHUUR.js} +29 -12
- package/dist/chunk-AP7IHUUR.js.map +1 -0
- package/dist/{chunk-QTTR7AAW.js → chunk-C6LL746C.js} +67 -84
- package/dist/{chunk-QTTR7AAW.js.map → chunk-C6LL746C.js.map} +1 -1
- package/dist/{chunk-W2PP3LEH.js → chunk-SEUZYQGQ.js} +17 -8
- package/dist/chunk-SEUZYQGQ.js.map +1 -0
- package/dist/{chunk-4BLCXNQ6.js → chunk-UBUC5A66.js} +105 -114
- package/dist/chunk-UBUC5A66.js.map +1 -0
- package/dist/{chunk-XXYOUIZY.js → chunk-VDU25Z6X.js} +63 -80
- package/dist/chunk-VDU25Z6X.js.map +1 -0
- package/dist/daily-log-processor-BY3ISY6K.js +9 -0
- package/dist/{daily-logs-store-D3QC2XPV.js → daily-logs-store-3C3OTGPK.js} +2 -2
- package/dist/iv-solver-worker.js +9 -1
- package/dist/market-provider-H3ARIVZ4.js +16 -0
- package/dist/{proto-3HZTCWK4.js → proto-V23GIZG2.js} +2 -2
- package/dist/{sync-PO4IPCYV.js → sync-EVLKB3ZJ.js} +7 -7
- package/dist/test-exports.js +358 -254
- package/dist/test-exports.js.map +1 -1
- package/dist/trade-processor-EYA3I3XB.js +9 -0
- package/dist/{trades-store-LOL3FQSF.js → trades-store-R3NL25T2.js} +2 -2
- package/manifest.json +3 -11
- package/package.json +1 -1
- package/server/{chunk-NZO6PT64.js → chunk-4P7D7YZP.js} +102 -113
- package/server/chunk-4P7D7YZP.js.map +1 -0
- package/server/{chunk-72GKJE2U.js → chunk-BOPHW5M6.js} +521 -235
- package/server/chunk-BOPHW5M6.js.map +1 -0
- package/server/{chunk-WA5AAPCH.js → chunk-GH2552SE.js} +17 -8
- package/server/chunk-GH2552SE.js.map +1 -0
- package/server/{chunk-5EBXHT6C.js → chunk-OBYKFW2B.js} +11 -13
- package/server/chunk-OBYKFW2B.js.map +1 -0
- package/server/{chunk-FBNDMCT5.js → chunk-T66KH2XH.js} +13 -11
- package/server/chunk-T66KH2XH.js.map +1 -0
- package/server/{chunk-NRFXAJF7.js → chunk-W5E7FHC4.js} +24 -52
- package/server/chunk-W5E7FHC4.js.map +1 -0
- package/server/{chunk-CSDVJPBB.js → chunk-YUCOAJ4Z.js} +29 -12
- package/server/chunk-YUCOAJ4Z.js.map +1 -0
- package/server/{chunk-PNKG7RY7.js → chunk-ZBJCF4ZG.js} +63 -80
- package/server/chunk-ZBJCF4ZG.js.map +1 -0
- package/server/{config-6IZXEFEX.js → config-DK7KOMNL.js} +1 -1
- package/server/config-DK7KOMNL.js.map +1 -0
- package/server/daily-log-processor-ENEUT22A.js +10 -0
- package/server/{daily-logs-store-NU7M4L5C.js → daily-logs-store-YFNXTB7J.js} +2 -2
- package/server/http-server.js +2 -5
- package/server/index.js +1771 -1538
- package/server/index.js.map +1 -1
- package/server/iv-solver-worker.js +9 -1
- package/server/market-provider-B437HKLW.js +17 -0
- package/server/{proto-DWRZJO4E.js → proto-YZ4TLX2N.js} +2 -2
- package/server/{sync-QFI5L7S7.js → sync-V25UQJA3.js} +7 -7
- package/server/trade-processor-L3PIQ5TG.js +10 -0
- package/server/{trades-store-VY26MWER.js → trades-store-RTTEYMXH.js} +2 -2
- package/src/auth/clients-store.ts +4 -4
- package/src/auth/code-store.ts +1 -1
- package/src/auth/config.ts +11 -12
- package/src/auth/login-page.ts +8 -10
- package/src/auth/provider.ts +35 -30
- package/src/auth/token.ts +17 -15
- package/src/db/backtest-schemas.ts +12 -4
- package/src/db/connection.ts +107 -40
- package/src/db/index.ts +37 -5
- package/src/db/json-adapters.ts +22 -31
- package/src/db/json-migration.ts +11 -15
- package/src/db/json-store.ts +5 -3
- package/src/db/market-datasets.ts +48 -15
- package/src/db/market-schemas.ts +11 -5
- package/src/db/market-views.ts +119 -32
- package/src/db/parquet-writer.ts +7 -7
- package/src/db/profile-schemas.ts +39 -22
- package/src/db/schemas.ts +2 -2
- package/src/http-server.ts +7 -12
- package/src/index.ts +8 -9
- package/src/market/ingestor/index.ts +1 -4
- package/src/market/ingestor/market-ingestor.ts +140 -67
- package/src/market/ingestor/types.ts +1 -3
- package/src/market/stores/chain-sql.ts +2 -8
- package/src/market/stores/chain-store.ts +1 -4
- package/src/market/stores/duckdb-chain-store.ts +3 -14
- package/src/market/stores/duckdb-enriched-store.ts +3 -13
- package/src/market/stores/duckdb-quote-store.ts +10 -27
- package/src/market/stores/duckdb-spot-store.ts +4 -20
- package/src/market/stores/enriched-sql.ts +3 -9
- package/src/market/stores/enriched-store.ts +2 -2
- package/src/market/stores/parquet-chain-store.ts +5 -22
- package/src/market/stores/parquet-enriched-store.ts +4 -16
- package/src/market/stores/parquet-oi-daily-store.ts +3 -14
- package/src/market/stores/parquet-quote-store.ts +9 -29
- package/src/market/stores/parquet-spot-store.ts +14 -33
- package/src/market/stores/quote-store.ts +2 -10
- package/src/market/stores/spot-sql.ts +3 -15
- package/src/market/stores/spot-store.ts +1 -1
- package/src/market/tickers/defaults.json +6 -6
- package/src/market/tickers/loader.ts +2 -7
- package/src/market/tickers/registry.ts +5 -15
- package/src/market/tickers/schemas.ts +2 -6
- package/src/models/strategy-profile.ts +39 -39
- package/src/sync/block-sync.ts +44 -65
- package/src/sync/index.ts +1 -4
- package/src/sync/metadata.ts +14 -20
- package/src/test-exports.ts +127 -123
- package/src/tools/analysis.ts +180 -159
- package/src/tools/batch-exit-analysis.ts +100 -59
- package/src/tools/blocks/analysis.ts +116 -101
- package/src/tools/blocks/comparison.ts +281 -364
- package/src/tools/blocks/core.ts +208 -253
- package/src/tools/blocks/health.ts +571 -563
- package/src/tools/blocks/similarity.ts +316 -283
- package/src/tools/edge-decay.ts +124 -197
- package/src/tools/exit-analysis.ts +130 -77
- package/src/tools/greeks-attribution.ts +84 -35
- package/src/tools/guides.ts +4 -6
- package/src/tools/imports.ts +9 -12
- package/src/tools/market-data.ts +1067 -757
- package/src/tools/market-enrichment.ts +3 -3
- package/src/tools/market-fetch.ts +148 -67
- package/src/tools/market-imports.ts +12 -12
- package/src/tools/middleware/sync-middleware.ts +5 -6
- package/src/tools/performance.ts +185 -302
- package/src/tools/profile-analysis.ts +52 -66
- package/src/tools/profiles.ts +106 -69
- package/src/tools/regime-advisor.ts +20 -45
- package/src/tools/replay.ts +81 -77
- package/src/tools/reports/discrepancies.ts +298 -328
- package/src/tools/reports/fields.ts +7 -25
- package/src/tools/reports/helpers.ts +18 -49
- package/src/tools/reports/predictive.ts +27 -70
- package/src/tools/reports/slippage-trends.ts +315 -345
- package/src/tools/reports/slippage.ts +1 -4
- package/src/tools/reports/strategy-matches.ts +399 -441
- package/src/tools/schema.ts +43 -40
- package/src/tools/shared/filters.ts +3 -9
- package/src/tools/snapshot.ts +9 -30
- package/src/tools/sql.ts +15 -14
- package/src/tools/tickers.ts +1 -4
- package/src/utils/batch-exit-analysis.ts +31 -42
- package/src/utils/black-scholes.ts +39 -29
- package/src/utils/block-loader.ts +68 -82
- package/src/utils/calibration-probe.ts +1 -2
- package/src/utils/chain-loader.ts +3 -3
- package/src/utils/csv-discovery.ts +16 -22
- package/src/utils/data-quality.ts +24 -36
- package/src/utils/exit-triggers.ts +91 -96
- package/src/utils/field-timing.ts +94 -79
- package/src/utils/filter-predicates.ts +13 -9
- package/src/utils/flatfile-importer.ts +94 -64
- package/src/utils/greeks-decomposition.ts +152 -100
- package/src/utils/iv-solver-pool.ts +55 -25
- package/src/utils/iv-solver-worker.ts +5 -5
- package/src/utils/market-enricher.ts +528 -497
- package/src/utils/market-importer.ts +31 -12
- package/src/utils/market-provider.ts +21 -23
- package/src/utils/massive-tier.ts +5 -7
- package/src/utils/migrate-option-data-helpers.ts +2 -8
- package/src/utils/option-quote-greeks.ts +25 -31
- package/src/utils/option-time.ts +4 -8
- package/src/utils/output-formatter.ts +1 -4
- package/src/utils/provider-capabilities.ts +1 -4
- package/src/utils/providers/massive.ts +59 -93
- package/src/utils/providers/thetadata/backfill.ts +14 -23
- package/src/utils/providers/thetadata/client.ts +12 -8
- package/src/utils/providers/thetadata/decode.ts +2 -20
- package/src/utils/providers/thetadata/endpoints.ts +32 -40
- package/src/utils/providers/thetadata/join.ts +11 -10
- package/src/utils/providers/thetadata/proto.ts +12 -10
- package/src/utils/providers/thetadata/quote-mid-greeks.ts +5 -5
- package/src/utils/providers/thetadata.ts +11 -10
- package/src/utils/quote-enricher.ts +4 -4
- package/src/utils/quote-parquet-projection.ts +3 -11
- package/src/utils/sample-date-selector.ts +3 -5
- package/src/utils/schema-metadata.ts +102 -70
- package/src/utils/ticker.ts +5 -9
- package/src/utils/trade-replay.ts +77 -68
- package/dist/chunk-4BLCXNQ6.js.map +0 -1
- package/dist/chunk-BKQ4PM4Y.js.map +0 -1
- package/dist/chunk-FGZH632F.js.map +0 -1
- package/dist/chunk-LDKTV7GW.js.map +0 -1
- package/dist/chunk-PRAYH3RT.js.map +0 -1
- package/dist/chunk-W2PP3LEH.js.map +0 -1
- package/dist/chunk-XXYOUIZY.js.map +0 -1
- package/dist/daily-log-processor-6MWJ23JK.js +0 -9
- package/dist/market-provider-VDRJUEF2.js +0 -16
- package/dist/trade-processor-NHU4VWRX.js +0 -9
- package/server/chunk-5EBXHT6C.js.map +0 -1
- package/server/chunk-72GKJE2U.js.map +0 -1
- package/server/chunk-CSDVJPBB.js.map +0 -1
- package/server/chunk-FBNDMCT5.js.map +0 -1
- package/server/chunk-NRFXAJF7.js.map +0 -1
- package/server/chunk-NZO6PT64.js.map +0 -1
- package/server/chunk-PNKG7RY7.js.map +0 -1
- package/server/chunk-WA5AAPCH.js.map +0 -1
- package/server/config-6IZXEFEX.js.map +0 -1
- package/server/daily-log-processor-Y3PVSVBM.js +0 -10
- package/server/market-provider-VOYYVYWT.js +0 -17
- package/server/trade-processor-JWVS37KM.js +0 -10
- /package/dist/{daily-log-processor-6MWJ23JK.js.map → daily-log-processor-BY3ISY6K.js.map} +0 -0
- /package/dist/{daily-logs-store-D3QC2XPV.js.map → daily-logs-store-3C3OTGPK.js.map} +0 -0
- /package/dist/{market-provider-VDRJUEF2.js.map → market-provider-H3ARIVZ4.js.map} +0 -0
- /package/dist/{proto-3HZTCWK4.js.map → proto-V23GIZG2.js.map} +0 -0
- /package/dist/{sync-PO4IPCYV.js.map → sync-EVLKB3ZJ.js.map} +0 -0
- /package/dist/{trade-processor-NHU4VWRX.js.map → trade-processor-EYA3I3XB.js.map} +0 -0
- /package/dist/{trades-store-LOL3FQSF.js.map → trades-store-R3NL25T2.js.map} +0 -0
- /package/server/{daily-log-processor-Y3PVSVBM.js.map → daily-log-processor-ENEUT22A.js.map} +0 -0
- /package/server/{daily-logs-store-NU7M4L5C.js.map → daily-logs-store-YFNXTB7J.js.map} +0 -0
- /package/server/{market-provider-VOYYVYWT.js.map → market-provider-B437HKLW.js.map} +0 -0
- /package/server/{proto-DWRZJO4E.js.map → proto-YZ4TLX2N.js.map} +0 -0
- /package/server/{sync-QFI5L7S7.js.map → sync-V25UQJA3.js.map} +0 -0
- /package/server/{trade-processor-JWVS37KM.js.map → trade-processor-L3PIQ5TG.js.map} +0 -0
- /package/server/{trades-store-VY26MWER.js.map → trades-store-RTTEYMXH.js.map} +0 -0
|
@@ -7,16 +7,18 @@ import * as protoLoader from "@grpc/proto-loader";
|
|
|
7
7
|
import protobuf from "protobufjs";
|
|
8
8
|
var moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
function protoCandidates() {
|
|
10
|
-
return Array.from(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
return Array.from(
|
|
11
|
+
/* @__PURE__ */ new Set([
|
|
12
|
+
resolve(moduleDir, "mdds.proto"),
|
|
13
|
+
resolve(moduleDir, "../../../mdds.proto"),
|
|
14
|
+
resolve(moduleDir, "../../../../server/mdds.proto"),
|
|
15
|
+
resolve(moduleDir, "../../../../dist/mdds.proto"),
|
|
16
|
+
resolve(process.cwd(), "packages/mcp-server/src/utils/providers/thetadata/mdds.proto"),
|
|
17
|
+
resolve(process.cwd(), "src/utils/providers/thetadata/mdds.proto"),
|
|
18
|
+
resolve(process.cwd(), "server/mdds.proto"),
|
|
19
|
+
resolve(process.cwd(), "dist/mdds.proto")
|
|
20
|
+
])
|
|
21
|
+
);
|
|
20
22
|
}
|
|
21
23
|
function resolveMddsProtoPath() {
|
|
22
24
|
const candidates = protoCandidates();
|
|
@@ -51,4 +53,4 @@ export {
|
|
|
51
53
|
loadMddsGrpcPackage,
|
|
52
54
|
loadMddsProtoRoot
|
|
53
55
|
};
|
|
54
|
-
//# sourceMappingURL=chunk-
|
|
56
|
+
//# sourceMappingURL=chunk-2E63THNI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/providers/thetadata/proto.ts"],"sourcesContent":["import { existsSync } from \"fs\";\nimport { dirname, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport * as grpc from \"@grpc/grpc-js\";\nimport * as protoLoader from \"@grpc/proto-loader\";\nimport protobuf from \"protobufjs\";\nimport type { Root } from \"protobufjs\";\n\nconst moduleDir = dirname(fileURLToPath(import.meta.url));\n\nfunction protoCandidates(): string[] {\n return Array.from(\n new Set([\n resolve(moduleDir, \"mdds.proto\"),\n resolve(moduleDir, \"../../../mdds.proto\"),\n resolve(moduleDir, \"../../../../server/mdds.proto\"),\n resolve(moduleDir, \"../../../../dist/mdds.proto\"),\n resolve(process.cwd(), \"packages/mcp-server/src/utils/providers/thetadata/mdds.proto\"),\n resolve(process.cwd(), \"src/utils/providers/thetadata/mdds.proto\"),\n resolve(process.cwd(), \"server/mdds.proto\"),\n resolve(process.cwd(), \"dist/mdds.proto\"),\n ]),\n );\n}\n\nexport function resolveMddsProtoPath(): string {\n const candidates = protoCandidates();\n const found = candidates.find((candidate) => existsSync(candidate));\n if (!found) {\n throw new Error(`ThetaData MDDS proto not found. Checked: ${candidates.join(\", \")}`);\n }\n return found;\n}\n\nlet grpcPackage: unknown | null = null;\nlet protobufRoot: Root | null = null;\n\nexport function loadMddsGrpcPackage(): unknown {\n if (!grpcPackage) {\n const definition = protoLoader.loadSync(resolveMddsProtoPath(), {\n longs: Number,\n enums: String,\n defaults: false,\n oneofs: true,\n bytes: Buffer,\n });\n grpcPackage = grpc.loadPackageDefinition(definition);\n }\n return grpcPackage;\n}\n\nexport function loadMddsProtoRoot(): Root {\n if (!protobufRoot) protobufRoot = protobuf.loadSync(resolveMddsProtoPath());\n return protobufRoot;\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,eAAe;AACjC,SAAS,qBAAqB;AAC9B,YAAY,UAAU;AACtB,YAAY,iBAAiB;AAC7B,OAAO,cAAc;AAGrB,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAExD,SAAS,kBAA4B;AACnC,SAAO,MAAM;AAAA,IACX,oBAAI,IAAI;AAAA,MACN,QAAQ,WAAW,YAAY;AAAA,MAC/B,QAAQ,WAAW,qBAAqB;AAAA,MACxC,QAAQ,WAAW,+BAA+B;AAAA,MAClD,QAAQ,WAAW,6BAA6B;AAAA,MAChD,QAAQ,QAAQ,IAAI,GAAG,8DAA8D;AAAA,MACrF,QAAQ,QAAQ,IAAI,GAAG,0CAA0C;AAAA,MACjE,QAAQ,QAAQ,IAAI,GAAG,mBAAmB;AAAA,MAC1C,QAAQ,QAAQ,IAAI,GAAG,iBAAiB;AAAA,IAC1C,CAAC;AAAA,EACH;AACF;AAEO,SAAS,uBAA+B;AAC7C,QAAM,aAAa,gBAAgB;AACnC,QAAM,QAAQ,WAAW,KAAK,CAAC,cAAc,WAAW,SAAS,CAAC;AAClE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,4CAA4C,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,EACrF;AACA,SAAO;AACT;AAEA,IAAI,cAA8B;AAClC,IAAI,eAA4B;AAEzB,SAAS,sBAA+B;AAC7C,MAAI,CAAC,aAAa;AAChB,UAAM,aAAyB,qBAAS,qBAAqB,GAAG;AAAA,MAC9D,OAAO;AAAA,MACP,OAAO;AAAA,MACP,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,IACT,CAAC;AACD,kBAAmB,2BAAsB,UAAU;AAAA,EACrD;AACA,SAAO;AACT;AAEO,SAAS,oBAA0B;AACxC,MAAI,CAAC,aAAc,gBAAe,SAAS,SAAS,qBAAqB,CAAC;AAC1E,SAAO;AACT;","names":[]}
|
|
@@ -36,9 +36,7 @@ var CSVParser = class _CSVParser {
|
|
|
36
36
|
if (headers.length === 0) {
|
|
37
37
|
throw new Error("No valid headers found");
|
|
38
38
|
}
|
|
39
|
-
const cleanHeaders = headers.map(
|
|
40
|
-
(header) => header.replace(/^\ufeff/, "").trim()
|
|
41
|
-
);
|
|
39
|
+
const cleanHeaders = headers.map((header) => header.replace(/^\ufeff/, "").trim());
|
|
42
40
|
let validRows = 0;
|
|
43
41
|
let processedRows = 0;
|
|
44
42
|
for (let i = 1; i < lines.length && processedRows < this.config.maxRows; i++) {
|
|
@@ -260,8 +258,8 @@ var rawTradeDataSchema = z.object({
|
|
|
260
258
|
"Date Opened": z.string().min(1, "Date Opened is required"),
|
|
261
259
|
"Time Opened": z.string().min(1, "Time Opened is required"),
|
|
262
260
|
"Opening Price": z.string().min(1, "Opening Price is required"),
|
|
263
|
-
|
|
264
|
-
|
|
261
|
+
Legs: z.string().min(1, "Legs description is required"),
|
|
262
|
+
Premium: z.string().min(1, "Premium is required"),
|
|
265
263
|
"Closing Price": z.string().optional(),
|
|
266
264
|
"Date Closed": z.string().optional(),
|
|
267
265
|
"Time Closed": z.string().optional(),
|
|
@@ -271,15 +269,15 @@ var rawTradeDataSchema = z.object({
|
|
|
271
269
|
"No. of Contracts": z.string().min(1, "Number of Contracts is required"),
|
|
272
270
|
"Funds at Close": z.string().min(1, "Funds at Close is required"),
|
|
273
271
|
"Margin Req.": z.string().min(1, "Margin Requirement is required"),
|
|
274
|
-
|
|
272
|
+
Strategy: z.string().min(1, "Strategy is required"),
|
|
275
273
|
"Opening Commissions + Fees": z.string().default("0"),
|
|
276
274
|
"Closing Commissions + Fees": z.string().optional(),
|
|
277
275
|
"Opening Short/Long Ratio": z.string().default("0"),
|
|
278
276
|
"Closing Short/Long Ratio": z.string().optional(),
|
|
279
277
|
"Opening VIX": z.string().optional(),
|
|
280
278
|
"Closing VIX": z.string().optional(),
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
Gap: z.string().optional(),
|
|
280
|
+
Movement: z.string().optional(),
|
|
283
281
|
"Max Profit": z.string().optional(),
|
|
284
282
|
"Max Loss": z.string().optional()
|
|
285
283
|
}).passthrough();
|
|
@@ -314,11 +312,11 @@ var tradeSchema = z.object({
|
|
|
314
312
|
customFields: z.record(z.string(), z.union([z.number(), z.string()])).optional()
|
|
315
313
|
});
|
|
316
314
|
var rawReportingTradeDataSchema = z.object({
|
|
317
|
-
|
|
315
|
+
Strategy: z.string().min(1, "Strategy is required"),
|
|
318
316
|
"Date Opened": z.string().min(1, "Date Opened is required"),
|
|
319
317
|
"Time Opened": z.string().optional(),
|
|
320
318
|
"Opening Price": z.string().min(1, "Opening Price is required"),
|
|
321
|
-
|
|
319
|
+
Legs: z.string().min(1, "Legs description is required"),
|
|
322
320
|
"Initial Premium": z.string().min(1, "Initial Premium is required"),
|
|
323
321
|
"No. of Contracts": z.string().min(1, "Number of Contracts is required"),
|
|
324
322
|
"P/L": z.string().min(1, "P/L is required"),
|
|
@@ -344,10 +342,10 @@ var reportingTradeSchema = z.object({
|
|
|
344
342
|
reasonForClose: z.string().optional()
|
|
345
343
|
});
|
|
346
344
|
var rawDailyLogDataSchema = z.object({
|
|
347
|
-
|
|
345
|
+
Date: z.string().min(1, "Date is required"),
|
|
348
346
|
"Net Liquidity": z.string().min(1, "Net Liquidity is required"),
|
|
349
347
|
"Current Funds": z.string().min(1, "Current Funds is required"),
|
|
350
|
-
|
|
348
|
+
Withdrawn: z.string().default("0"),
|
|
351
349
|
"Trading Funds": z.string().min(1, "Trading Funds is required"),
|
|
352
350
|
"P/L": z.string().min(1, "P/L is required"),
|
|
353
351
|
"P/L %": z.string().min(1, "P/L % is required"),
|
|
@@ -439,4 +437,4 @@ export {
|
|
|
439
437
|
normalizeHeaders,
|
|
440
438
|
findMissingHeaders
|
|
441
439
|
};
|
|
442
|
-
//# sourceMappingURL=chunk-
|
|
440
|
+
//# sourceMappingURL=chunk-6S37CXUA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../lib/processing/csv-parser.ts","../../lib/models/validators.ts","../../lib/utils/csv-headers.ts"],"sourcesContent":["/**\n * CSV Parser Service\n *\n * Handles CSV file parsing with progress tracking, error handling,\n * and validation for TradeBlocks data.\n */\n\nimport type { ParsingError } from \"../models/index.ts\";\n// import { ProcessingError } from '../models/index.ts'\n\n/**\n * CSV parsing configuration\n */\nexport interface CSVParseConfig {\n delimiter?: string;\n quote?: string;\n escape?: string;\n skipEmptyLines?: boolean;\n trimValues?: boolean;\n maxRows?: number;\n progressCallback?: (progress: number, rowsProcessed: number) => void;\n}\n\n/**\n * CSV parsing result\n */\nexport interface CSVParseResult<T = Record<string, string>> {\n data: T[];\n headers: string[];\n totalRows: number;\n validRows: number;\n errors: ParsingError[];\n warnings: string[];\n}\n\n/**\n * CSV parsing progress info\n */\nexport interface ParseProgress {\n stage: \"reading\" | \"parsing\" | \"validating\" | \"converting\" | \"completed\";\n progress: number; // 0-100\n rowsProcessed: number;\n totalRows: number;\n errors: number;\n}\n\n/**\n * Base CSV parser class with streaming support for large files\n */\nexport class CSVParser {\n private config: Required<CSVParseConfig>;\n\n constructor(config: CSVParseConfig = {}) {\n this.config = {\n delimiter: \",\",\n quote: '\"',\n escape: '\"',\n skipEmptyLines: true,\n trimValues: true,\n maxRows: 100000, // Safety limit\n progressCallback: () => {},\n ...config,\n };\n }\n\n /**\n * Parse CSV file content\n */\n async parseFile<T = Record<string, string>>(\n fileContent: string,\n validator?: (row: Record<string, string>, rowIndex: number) => T | null,\n ): Promise<CSVParseResult<T>> {\n const errors: ParsingError[] = [];\n const warnings: string[] = [];\n const data: T[] = [];\n\n try {\n // Split into lines and handle different line endings\n const lines = fileContent.split(/\\r?\\n/);\n const totalRows = lines.length;\n\n if (totalRows === 0) {\n throw new Error(\"Empty CSV file\");\n }\n\n // Parse headers\n const headerLine = lines[0];\n if (!headerLine || headerLine.trim() === \"\") {\n throw new Error(\"Missing CSV headers\");\n }\n\n const headers = this.parseLine(headerLine);\n if (headers.length === 0) {\n throw new Error(\"No valid headers found\");\n }\n\n // Clean headers (remove BOM, trim whitespace)\n const cleanHeaders = headers.map((header) => header.replace(/^\\ufeff/, \"\").trim());\n\n let validRows = 0;\n let processedRows = 0;\n\n // Process data rows\n for (let i = 1; i < lines.length && processedRows < this.config.maxRows; i++) {\n const line = lines[i];\n\n // Skip empty lines if configured\n if (this.config.skipEmptyLines && (!line || line.trim() === \"\")) {\n continue;\n }\n\n processedRows++;\n\n try {\n const values = this.parseLine(line);\n\n // Create row object\n const row: Record<string, string> = {};\n cleanHeaders.forEach((header, index) => {\n const value = values[index] || \"\";\n row[header] = this.config.trimValues ? value.trim() : value;\n });\n\n // Validate row if validator provided\n if (validator) {\n const validatedRow = validator(row, i);\n if (validatedRow) {\n data.push(validatedRow);\n validRows++;\n }\n } else {\n data.push(row as T);\n validRows++;\n }\n } catch (error) {\n const parsingError: ParsingError = {\n type: \"parsing\",\n message: `Error parsing line ${i + 1}: ${error instanceof Error ? error.message : String(error)}`,\n details: { lineNumber: i + 1, line },\n line: i + 1,\n raw: line,\n };\n errors.push(parsingError);\n }\n\n // Report progress\n if (processedRows % 100 === 0 || processedRows === totalRows - 1) {\n const progress = Math.round((processedRows / (totalRows - 1)) * 100);\n this.config.progressCallback(progress, processedRows);\n }\n }\n\n // Check for truncation\n if (processedRows >= this.config.maxRows && lines.length > this.config.maxRows + 1) {\n warnings.push(`File truncated at ${this.config.maxRows} rows for performance`);\n }\n\n return {\n data,\n headers: cleanHeaders,\n totalRows: totalRows - 1, // Excluding header\n validRows,\n errors,\n warnings,\n };\n } catch (error) {\n const parsingError: ParsingError = {\n type: \"parsing\",\n message: `CSV parsing failed: ${error instanceof Error ? error.message : String(error)}`,\n details: { fileContent: fileContent.substring(0, 500) + \"...\" },\n line: 0,\n raw: \"\",\n };\n\n return {\n data: [],\n headers: [],\n totalRows: 0,\n validRows: 0,\n errors: [parsingError],\n warnings,\n };\n }\n }\n\n /**\n * Parse CSV from File object with progress tracking\n */\n async parseFileObject<T = Record<string, string>>(\n file: File,\n validator?: (row: Record<string, string>, rowIndex: number) => T | null,\n progressCallback?: (progress: ParseProgress) => void,\n ): Promise<CSVParseResult<T>> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n\n reader.onprogress = (event) => {\n if (event.lengthComputable && progressCallback) {\n const progress = Math.round((event.loaded / event.total) * 100);\n progressCallback({\n stage: \"reading\",\n progress,\n rowsProcessed: 0,\n totalRows: 0,\n errors: 0,\n });\n }\n };\n\n reader.onload = async (event) => {\n try {\n const content = event.target?.result as string;\n if (!content) {\n throw new Error(\"Failed to read file content\");\n }\n\n // Update progress callback for parsing stage\n const parseConfig = {\n ...this.config,\n progressCallback: (progress: number, rowsProcessed: number) => {\n if (progressCallback) {\n progressCallback({\n stage: \"parsing\",\n progress,\n rowsProcessed,\n totalRows: content.split(/\\r?\\n/).length - 1,\n errors: 0,\n });\n }\n },\n };\n\n const parser = new CSVParser(parseConfig);\n const result = await parser.parseFile(content, validator);\n\n if (progressCallback) {\n progressCallback({\n stage: \"completed\",\n progress: 100,\n rowsProcessed: result.validRows,\n totalRows: result.totalRows,\n errors: result.errors.length,\n });\n }\n\n resolve(result);\n } catch (error) {\n reject(error);\n }\n };\n\n reader.onerror = () => {\n reject(new Error(\"Failed to read file\"));\n };\n\n reader.readAsText(file);\n });\n }\n\n /**\n * Parse a single CSV line, handling quoted values and escapes\n */\n private parseLine(line: string): string[] {\n const result: string[] = [];\n const { delimiter, quote, escape } = this.config;\n\n let current = \"\";\n let inQuotes = false;\n let i = 0;\n\n while (i < line.length) {\n const char = line[i];\n const nextChar = line[i + 1];\n\n if (!inQuotes) {\n if (char === delimiter) {\n result.push(current);\n current = \"\";\n } else if (char === quote) {\n inQuotes = true;\n } else {\n current += char;\n }\n } else {\n if (char === escape && nextChar === quote) {\n // Escaped quote\n current += quote;\n i++; // Skip next character\n } else if (char === quote) {\n inQuotes = false;\n } else {\n current += char;\n }\n }\n\n i++;\n }\n\n // Add the last field\n result.push(current);\n\n return result;\n }\n\n /**\n * Validate CSV file format before parsing\n */\n static validateCSVFile(file: File): { valid: boolean; error?: string } {\n // Check file type\n const validTypes = [\"text/csv\", \"application/vnd.ms-excel\", \"text/plain\"];\n if (!validTypes.includes(file.type) && !file.name.toLowerCase().endsWith(\".csv\")) {\n return { valid: false, error: \"File must be a CSV file (.csv extension)\" };\n }\n\n // Check file size (50MB limit)\n const maxSize = 50 * 1024 * 1024;\n if (file.size > maxSize) {\n return { valid: false, error: \"File size must be less than 50MB\" };\n }\n\n // Check for empty file\n if (file.size === 0) {\n return { valid: false, error: \"File is empty\" };\n }\n\n return { valid: true };\n }\n\n /**\n * Detect CSV delimiter from sample content\n */\n static detectDelimiter(sampleContent: string): string {\n const delimiters = [\",\", \";\", \"\\t\", \"|\"];\n const lines = sampleContent.split(/\\r?\\n/).slice(0, 5); // Check first 5 lines\n\n let bestDelimiter = \",\";\n let maxScore = 0;\n\n for (const delimiter of delimiters) {\n let score = 0;\n let consistentCounts = true;\n let expectedCount = -1;\n\n for (const line of lines) {\n if (!line.trim()) continue;\n\n const count = line.split(delimiter).length - 1;\n if (expectedCount === -1) {\n expectedCount = count;\n } else if (count !== expectedCount) {\n consistentCounts = false;\n break;\n }\n score += count;\n }\n\n if (consistentCounts && score > maxScore) {\n maxScore = score;\n bestDelimiter = delimiter;\n }\n }\n\n return bestDelimiter;\n }\n}\n","import { z } from \"zod\";\n\n/**\n * Zod schema for validating raw trade data from CSV\n */\nexport const rawTradeDataSchema = z\n .object({\n \"Date Opened\": z.string().min(1, \"Date Opened is required\"),\n \"Time Opened\": z.string().min(1, \"Time Opened is required\"),\n \"Opening Price\": z.string().min(1, \"Opening Price is required\"),\n Legs: z.string().min(1, \"Legs description is required\"),\n Premium: z.string().min(1, \"Premium is required\"),\n \"Closing Price\": z.string().optional(),\n \"Date Closed\": z.string().optional(),\n \"Time Closed\": z.string().optional(),\n \"Avg. Closing Cost\": z.string().optional(),\n \"Reason For Close\": z.string().optional(),\n \"P/L\": z.string().min(1, \"P/L is required\"),\n \"No. of Contracts\": z.string().min(1, \"Number of Contracts is required\"),\n \"Funds at Close\": z.string().min(1, \"Funds at Close is required\"),\n \"Margin Req.\": z.string().min(1, \"Margin Requirement is required\"),\n Strategy: z.string().min(1, \"Strategy is required\"),\n \"Opening Commissions + Fees\": z.string().default(\"0\"),\n \"Closing Commissions + Fees\": z.string().optional(),\n \"Opening Short/Long Ratio\": z.string().default(\"0\"),\n \"Closing Short/Long Ratio\": z.string().optional(),\n \"Opening VIX\": z.string().optional(),\n \"Closing VIX\": z.string().optional(),\n Gap: z.string().optional(),\n Movement: z.string().optional(),\n \"Max Profit\": z.string().optional(),\n \"Max Loss\": z.string().optional(),\n })\n .passthrough(); // Allow custom columns to pass through validation\n\n/**\n * Zod schema for validating processed trade data\n */\nexport const tradeSchema = z.object({\n dateOpened: z.date(),\n timeOpened: z\n .string()\n .regex(/^\\d{1,2}:\\d{2}:\\d{2}$/, \"Time must be in H:mm:ss or HH:mm:ss format\"),\n openingPrice: z.number().finite(),\n legs: z.string().min(1),\n premium: z.number().finite(),\n premiumPrecision: z.enum([\"dollars\", \"cents\"]).optional(),\n closingPrice: z.number().finite().optional(),\n dateClosed: z.date().optional(),\n timeClosed: z\n .string()\n .regex(/^\\d{1,2}:\\d{2}:\\d{2}$/)\n .optional(),\n avgClosingCost: z.number().finite().optional(),\n reasonForClose: z.string().optional(),\n pl: z.number().finite(),\n numContracts: z.number().int().positive(),\n fundsAtClose: z.number().finite(),\n marginReq: z.number().finite().min(0),\n strategy: z.string().min(1),\n openingCommissionsFees: z.number().finite().min(0),\n closingCommissionsFees: z.number().finite().min(0),\n openingShortLongRatio: z.number().finite().min(0),\n closingShortLongRatio: z.number().finite().min(0).optional(),\n openingVix: z.number().finite().min(0).optional(),\n closingVix: z.number().finite().min(0).optional(),\n gap: z.number().finite().optional(),\n movement: z.number().finite().optional(),\n maxProfit: z.number().finite().optional(),\n maxLoss: z.number().finite().optional(),\n syntheticCapitalRatio: z.number().finite().optional(),\n customFields: z.record(z.string(), z.union([z.number(), z.string()])).optional(),\n});\n\n/**\n * Zod schema for validating raw reporting trade data from strategy logs\n */\nexport const rawReportingTradeDataSchema = z.object({\n Strategy: z.string().min(1, \"Strategy is required\"),\n \"Date Opened\": z.string().min(1, \"Date Opened is required\"),\n \"Time Opened\": z.string().optional(),\n \"Opening Price\": z.string().min(1, \"Opening Price is required\"),\n Legs: z.string().min(1, \"Legs description is required\"),\n \"Initial Premium\": z.string().min(1, \"Initial Premium is required\"),\n \"No. of Contracts\": z.string().min(1, \"Number of Contracts is required\"),\n \"P/L\": z.string().min(1, \"P/L is required\"),\n \"Closing Price\": z.string().optional(),\n \"Date Closed\": z.string().optional(),\n \"Time Closed\": z.string().optional(),\n \"Avg. Closing Cost\": z.string().optional(),\n \"Reason For Close\": z.string().optional(),\n});\n\n/**\n * Zod schema for validating processed reporting trade data\n */\nexport const reportingTradeSchema = z.object({\n strategy: z.string().min(1),\n dateOpened: z.date(),\n timeOpened: z.string().optional(),\n openingPrice: z.number().finite(),\n legs: z.string().min(1),\n initialPremium: z.number().finite(),\n numContracts: z.number().finite(),\n pl: z.number().finite(),\n closingPrice: z.number().finite().optional(),\n dateClosed: z.date().optional(),\n timeClosed: z.string().optional(),\n avgClosingCost: z.number().finite().optional(),\n reasonForClose: z.string().optional(),\n});\n\n/**\n * Zod schema for validating raw daily log data from CSV\n */\nexport const rawDailyLogDataSchema = z\n .object({\n Date: z.string().min(1, \"Date is required\"),\n \"Net Liquidity\": z.string().min(1, \"Net Liquidity is required\"),\n \"Current Funds\": z.string().min(1, \"Current Funds is required\"),\n Withdrawn: z.string().default(\"0\"),\n \"Trading Funds\": z.string().min(1, \"Trading Funds is required\"),\n \"P/L\": z.string().min(1, \"P/L is required\"),\n \"P/L %\": z.string().min(1, \"P/L % is required\"),\n \"Drawdown %\": z.string().min(1, \"Drawdown % is required\"),\n })\n .passthrough(); // Allow custom columns to pass through validation\n\n/**\n * Zod schema for validating processed daily log entry\n */\nexport const dailyLogEntrySchema = z.object({\n date: z.date(),\n netLiquidity: z.number().finite(),\n currentFunds: z.number().finite(),\n withdrawn: z.number().finite().min(0),\n tradingFunds: z.number().finite().min(0),\n dailyPl: z.number().finite(),\n dailyPlPct: z.number().finite(),\n drawdownPct: z.number().finite().max(0), // Drawdown should be negative or zero\n blockId: z.string().optional(),\n customFields: z.record(z.string(), z.union([z.number(), z.string()])).optional(),\n});\n\n/**\n * Zod schema for portfolio statistics\n */\nexport const portfolioStatsSchema = z.object({\n totalTrades: z.number().int().min(0),\n totalPl: z.number().finite(),\n winRate: z.number().min(0).max(1),\n avgWin: z.number().finite().min(0),\n avgLoss: z.number().finite().max(0),\n maxWin: z.number().finite().min(0),\n maxLoss: z.number().finite().max(0),\n sharpeRatio: z.number().finite().optional(),\n maxDrawdown: z.number().finite().max(0),\n avgDailyPl: z.number().finite(),\n totalCommissions: z.number().finite().min(0),\n netPl: z.number().finite(),\n profitFactor: z.number().finite().min(0),\n});\n\n/**\n * Zod schema for strategy statistics\n */\nexport const strategyStatsSchema = z.object({\n strategyName: z.string().min(1),\n tradeCount: z.number().int().min(0),\n totalPl: z.number().finite(),\n winRate: z.number().min(0).max(1),\n avgWin: z.number().finite().min(0),\n avgLoss: z.number().finite().max(0),\n maxWin: z.number().finite().min(0),\n maxLoss: z.number().finite().max(0),\n avgDte: z.number().finite().min(0).optional(),\n successRate: z.number().min(0).max(1),\n profitFactor: z.number().finite().min(0),\n});\n\n/**\n * Zod schema for analysis configuration\n */\nexport const analysisConfigSchema = z.object({\n useBusinessDaysOnly: z.boolean(),\n annualizationFactor: z.number().int().min(200).max(365),\n confidenceLevel: z.number().min(0.8).max(0.99),\n});\n\n/**\n * Zod schema for file validation\n */\nexport const fileSchema = z.object({\n name: z.string().min(1),\n size: z.number().int().positive(),\n type: z\n .string()\n .refine(\n (type) => type === \"text/csv\" || type === \"application/vnd.ms-excel\",\n \"File must be a CSV file\",\n ),\n});\n\n/**\n * Zod schema for block creation request\n */\nexport const createBlockRequestSchema = z.object({\n name: z.string().min(1).max(100),\n description: z.string().max(500).optional(),\n analysisConfig: analysisConfigSchema.partial().optional(),\n});\n\n/**\n * Type exports for use with TypeScript\n */\nexport type RawTradeData = z.infer<typeof rawTradeDataSchema>;\nexport type ValidatedTrade = z.infer<typeof tradeSchema>;\nexport type RawReportingTradeData = z.infer<typeof rawReportingTradeDataSchema>;\nexport type ValidatedReportingTrade = z.infer<typeof reportingTradeSchema>;\nexport type RawDailyLogData = z.infer<typeof rawDailyLogDataSchema>;\nexport type ValidatedDailyLogEntry = z.infer<typeof dailyLogEntrySchema>;\nexport type ValidatedPortfolioStats = z.infer<typeof portfolioStatsSchema>;\nexport type ValidatedStrategyStats = z.infer<typeof strategyStatsSchema>;\nexport type ValidatedAnalysisConfig = z.infer<typeof analysisConfigSchema>;\nexport type ValidatedFile = z.infer<typeof fileSchema>;\nexport type ValidatedCreateBlockRequest = z.infer<typeof createBlockRequestSchema>;\n","/**\n * CSV header utilities\n */\n\nexport interface HeaderValidationOptions {\n /** Optional map of alternate header names to canonical names */\n aliases?: Record<string, string> | Readonly<Record<string, string>>;\n /** Human-readable label used in error messages */\n contextLabel?: string;\n}\n\nconst BOM = \"\\uFEFF\";\n\n/**\n * Remove UTF-8 byte order mark from a string if present\n */\nexport function stripBom(value: string): string {\n return value.startsWith(BOM) ? value.slice(1) : value;\n}\n\n/**\n * Parse a single CSV line into values, handling quoted fields and commas\n */\nexport function parseCsvLine(line: string): string[] {\n const result: string[] = [];\n let current = \"\";\n let inQuotes = false;\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n\n if (char === '\"') {\n const nextChar = line[i + 1];\n if (inQuotes && nextChar === '\"') {\n // Escaped quote inside quoted value\n current += '\"';\n i++;\n } else {\n inQuotes = !inQuotes;\n }\n continue;\n }\n\n if (char === \",\" && !inQuotes) {\n result.push(current.trim());\n current = \"\";\n } else {\n current += char;\n }\n }\n\n result.push(current.trim());\n\n if (result.length > 0) {\n result[0] = stripBom(result[0]);\n }\n\n return result;\n}\n\n/**\n * Normalize a CSV header by trimming whitespace, stripping BOM, and applying aliases\n */\nexport function normalizeHeader(\n header: string,\n aliases?: Record<string, string> | Readonly<Record<string, string>>,\n): string {\n const trimmed = stripBom(header).trim();\n return aliases?.[trimmed] ?? trimmed;\n}\n\n/**\n * Normalize an array of headers\n */\nexport function normalizeHeaders(\n headers: string[],\n aliases?: Record<string, string> | Readonly<Record<string, string>>,\n): string[] {\n return headers.map((header) => normalizeHeader(header, aliases));\n}\n\n/**\n * Validate that required headers are present. Returns the missing headers without throwing.\n */\nexport function findMissingHeaders(headers: string[], required: readonly string[]): string[] {\n const headerSet = new Set(headers);\n return required.filter((requiredHeader) => !headerSet.has(requiredHeader));\n}\n\n/**\n * Ensure required headers are present, throwing an Error with a helpful message when missing.\n */\nexport function assertRequiredHeaders(\n headers: string[],\n required: readonly string[],\n options: HeaderValidationOptions = {},\n): void {\n const missing = findMissingHeaders(headers, required);\n if (missing.length === 0) {\n return;\n }\n\n const label = options.contextLabel ? `${options.contextLabel} ` : \"\";\n throw new Error(`Missing required ${label}columns: ${missing.join(\", \")}`);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
normalizeHeaders,
|
|
5
5
|
rawTradeDataSchema,
|
|
6
6
|
tradeSchema
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6S37CXUA.js";
|
|
8
8
|
|
|
9
9
|
// ../lib/models/trade.ts
|
|
10
10
|
var TRADE_COLUMN_MAPPING = {
|
|
11
11
|
"Date Opened": "dateOpened",
|
|
12
12
|
"Time Opened": "timeOpened",
|
|
13
13
|
"Opening Price": "openingPrice",
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
Legs: "legs",
|
|
15
|
+
Premium: "premium",
|
|
16
16
|
"Closing Price": "closingPrice",
|
|
17
17
|
"Date Closed": "dateClosed",
|
|
18
18
|
"Time Closed": "timeClosed",
|
|
@@ -22,15 +22,15 @@ var TRADE_COLUMN_MAPPING = {
|
|
|
22
22
|
"No. of Contracts": "numContracts",
|
|
23
23
|
"Funds at Close": "fundsAtClose",
|
|
24
24
|
"Margin Req.": "marginReq",
|
|
25
|
-
|
|
25
|
+
Strategy: "strategy",
|
|
26
26
|
"Opening Commissions + Fees": "openingCommissionsFees",
|
|
27
27
|
"Closing Commissions + Fees": "closingCommissionsFees",
|
|
28
28
|
"Opening Short/Long Ratio": "openingShortLongRatio",
|
|
29
29
|
"Closing Short/Long Ratio": "closingShortLongRatio",
|
|
30
30
|
"Opening VIX": "openingVix",
|
|
31
31
|
"Closing VIX": "closingVix",
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
Gap: "gap",
|
|
33
|
+
Movement: "movement",
|
|
34
34
|
"Max Profit": "maxProfit",
|
|
35
35
|
"Max Loss": "maxLoss"
|
|
36
36
|
};
|
|
@@ -273,7 +273,10 @@ var TradeProcessor = class {
|
|
|
273
273
|
rawTradeDataSchema.parse(normalizedRow);
|
|
274
274
|
return normalizedRow;
|
|
275
275
|
} catch (error) {
|
|
276
|
-
console.warn(
|
|
276
|
+
console.warn(
|
|
277
|
+
`[TradeProcessor] Row ${rowIndex + 2} validation failed:`,
|
|
278
|
+
error instanceof Error ? error.message : error
|
|
279
|
+
);
|
|
277
280
|
return null;
|
|
278
281
|
}
|
|
279
282
|
}
|
|
@@ -341,9 +344,21 @@ var TradeProcessor = class {
|
|
|
341
344
|
fundsAtClose: parseNumber(rawData["Funds at Close"], "Funds at Close"),
|
|
342
345
|
marginReq: parseNumber(rawData["Margin Req."], "Margin Req."),
|
|
343
346
|
strategy,
|
|
344
|
-
openingCommissionsFees: parseNumber(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
+
openingCommissionsFees: parseNumber(
|
|
348
|
+
rawData["Opening Commissions + Fees"],
|
|
349
|
+
"Opening Commissions",
|
|
350
|
+
0
|
|
351
|
+
),
|
|
352
|
+
closingCommissionsFees: parseNumber(
|
|
353
|
+
rawData["Closing Commissions + Fees"],
|
|
354
|
+
"Closing Commissions",
|
|
355
|
+
0
|
|
356
|
+
),
|
|
357
|
+
openingShortLongRatio: parseNumber(
|
|
358
|
+
rawData["Opening Short/Long Ratio"],
|
|
359
|
+
"Opening Short/Long Ratio",
|
|
360
|
+
0
|
|
361
|
+
),
|
|
347
362
|
closingShortLongRatio: rawData["Closing Short/Long Ratio"] ? parseNumber(rawData["Closing Short/Long Ratio"], "Closing Short/Long Ratio") : void 0,
|
|
348
363
|
openingVix: rawData["Opening VIX"] ? parseNumber(rawData["Opening VIX"], "Opening VIX") : void 0,
|
|
349
364
|
closingVix: rawData["Closing VIX"] ? parseNumber(rawData["Closing VIX"], "Closing VIX") : void 0,
|
|
@@ -370,7 +385,9 @@ var TradeProcessor = class {
|
|
|
370
385
|
const validatedTrade = tradeSchema.parse(trade);
|
|
371
386
|
return validatedTrade;
|
|
372
387
|
} catch (error) {
|
|
373
|
-
throw new Error(
|
|
388
|
+
throw new Error(
|
|
389
|
+
`Trade conversion failed: ${error instanceof Error ? error.message : String(error)}`
|
|
390
|
+
);
|
|
374
391
|
}
|
|
375
392
|
}
|
|
376
393
|
/**
|
|
@@ -386,4 +403,4 @@ var TradeProcessor = class {
|
|
|
386
403
|
export {
|
|
387
404
|
TradeProcessor
|
|
388
405
|
};
|
|
389
|
-
//# sourceMappingURL=chunk-
|
|
406
|
+
//# sourceMappingURL=chunk-AP7IHUUR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../lib/models/trade.ts","../../lib/processing/trade-processor.ts"],"sourcesContent":["/**\n * Trade model based on legacy Python Trade class\n * Represents individual trade record from portfolio CSV\n */\nexport interface Trade {\n // Core trade identification\n dateOpened: Date;\n timeOpened: string; // HH:mm:ss format\n openingPrice: number;\n legs: string; // Option legs description\n premium: number;\n /**\n * Records how the premium value was encoded in the source CSV.\n * Some exports (OptionOmega) provide cents as whole numbers without decimals.\n */\n premiumPrecision?: \"dollars\" | \"cents\";\n\n // Closing information (optional for open trades)\n closingPrice?: number;\n dateClosed?: Date;\n timeClosed?: string;\n avgClosingCost?: number;\n reasonForClose?: string;\n\n // Financial metrics\n pl: number; // Profit/Loss\n numContracts: number;\n fundsAtClose: number;\n marginReq: number;\n\n // Trade metadata\n strategy: string;\n openingCommissionsFees: number;\n closingCommissionsFees: number;\n\n // Ratios and market data\n openingShortLongRatio: number;\n closingShortLongRatio?: number;\n openingVix?: number;\n closingVix?: number;\n\n // Additional metrics\n gap?: number;\n movement?: number;\n maxProfit?: number;\n maxLoss?: number;\n /**\n * Synthetic-only: ratio of the worst observed loss to account capital at the time\n * Used to scale synthetic losses relative to current account size\n */\n syntheticCapitalRatio?: number;\n\n /**\n * Custom fields from extra columns in the trade CSV\n * Keys are the original column names, values are auto-detected as number or string\n */\n customFields?: Record<string, number | string>;\n}\n\n/**\n * Raw trade data as it comes from CSV before processing\n */\nexport interface RawTradeData {\n \"Date Opened\": string;\n \"Time Opened\": string;\n \"Opening Price\": string;\n Legs: string;\n Premium: string;\n \"Closing Price\"?: string;\n \"Date Closed\"?: string;\n \"Time Closed\"?: string;\n \"Avg. Closing Cost\"?: string;\n \"Reason For Close\"?: string;\n \"P/L\": string;\n \"No. of Contracts\": string;\n \"Funds at Close\": string;\n \"Margin Req.\": string;\n Strategy: string;\n \"Opening Commissions + Fees\": string;\n \"Closing Commissions + Fees\"?: string;\n \"Opening Short/Long Ratio\": string;\n \"Closing Short/Long Ratio\"?: string;\n \"Opening VIX\"?: string;\n \"Closing VIX\"?: string;\n Gap?: string;\n Movement?: string;\n \"Max Profit\"?: string;\n \"Max Loss\"?: string;\n}\n\n/**\n * Column mapping from CSV headers to Trade interface properties\n */\nexport const TRADE_COLUMN_MAPPING = {\n \"Date Opened\": \"dateOpened\",\n \"Time Opened\": \"timeOpened\",\n \"Opening Price\": \"openingPrice\",\n Legs: \"legs\",\n Premium: \"premium\",\n \"Closing Price\": \"closingPrice\",\n \"Date Closed\": \"dateClosed\",\n \"Time Closed\": \"timeClosed\",\n \"Avg. Closing Cost\": \"avgClosingCost\",\n \"Reason For Close\": \"reasonForClose\",\n \"P/L\": \"pl\",\n \"No. of Contracts\": \"numContracts\",\n \"Funds at Close\": \"fundsAtClose\",\n \"Margin Req.\": \"marginReq\",\n Strategy: \"strategy\",\n \"Opening Commissions + Fees\": \"openingCommissionsFees\",\n \"Closing Commissions + Fees\": \"closingCommissionsFees\",\n \"Opening Short/Long Ratio\": \"openingShortLongRatio\",\n \"Closing Short/Long Ratio\": \"closingShortLongRatio\",\n \"Opening VIX\": \"openingVix\",\n \"Closing VIX\": \"closingVix\",\n Gap: \"gap\",\n Movement: \"movement\",\n \"Max Profit\": \"maxProfit\",\n \"Max Loss\": \"maxLoss\",\n} as const;\n\n/**\n * Column aliases for different CSV export variations\n */\nexport const TRADE_COLUMN_ALIASES = {\n \"Opening comms & fees\": \"Opening Commissions + Fees\",\n \"Opening Commissions & Fees\": \"Opening Commissions + Fees\",\n \"Closing comms & fees\": \"Closing Commissions + Fees\",\n \"Closing Commissions & Fees\": \"Closing Commissions + Fees\",\n \"P/L %\": \"P/L %\", // Recognized but ignored (we calculate our own plPct)\n} as const;\n\n/**\n * Minimum required columns for a valid trade log\n */\nexport const REQUIRED_TRADE_COLUMNS = [\n \"Date Opened\",\n \"Time Opened\",\n \"Opening Price\",\n \"Legs\",\n \"Premium\",\n \"Closing Price\",\n \"Date Closed\",\n \"Time Closed\",\n \"Avg. Closing Cost\",\n \"Reason For Close\",\n \"P/L\",\n \"No. of Contracts\",\n \"Funds at Close\",\n \"Margin Req.\",\n \"Strategy\",\n] as const;\n","/**\n * Trade Processor\n *\n * Handles parsing and processing of trade log CSV files from OptionOmega.\n * Converts raw CSV data to validated Trade objects.\n */\n\nimport {\n type Trade,\n TRADE_COLUMN_ALIASES,\n REQUIRED_TRADE_COLUMNS,\n TRADE_COLUMN_MAPPING,\n} from \"../models/trade.ts\";\nimport type { ValidationError, ProcessingError } from \"../models/index.ts\";\nimport { rawTradeDataSchema, tradeSchema } from \"../models/validators.ts\";\nimport { CSVParser, type ParseProgress } from \"./csv-parser.ts\";\nimport { findMissingHeaders, normalizeHeaders } from \"../utils/csv-headers.ts\";\n\n/**\n * Set of known trade column names (canonical names from TRADE_COLUMN_MAPPING)\n * Used to identify custom columns that should be preserved\n */\nconst KNOWN_TRADE_COLUMNS = new Set([\n ...Object.keys(TRADE_COLUMN_MAPPING),\n ...Object.keys(TRADE_COLUMN_ALIASES),\n]);\n\n/**\n * Trade processing configuration\n */\nexport interface TradeProcessingConfig {\n maxTrades?: number;\n strictValidation?: boolean;\n progressCallback?: (progress: TradeProcessingProgress) => void;\n}\n\n/**\n * Trade processing progress\n */\nexport interface TradeProcessingProgress extends ParseProgress {\n stage: \"reading\" | \"parsing\" | \"validating\" | \"converting\" | \"completed\";\n validTrades: number;\n invalidTrades: number;\n}\n\n/**\n * Trade processing result\n */\nexport interface TradeProcessingResult {\n trades: Trade[];\n totalRows: number;\n validTrades: number;\n invalidTrades: number;\n errors: ProcessingError[];\n warnings: string[];\n stats: {\n processingTimeMs: number;\n strategies: string[];\n dateRange: { start: Date | null; end: Date | null };\n totalPL: number;\n };\n}\n\n/**\n * Trade processor class\n */\nexport class TradeProcessor {\n private config: Required<TradeProcessingConfig>;\n\n constructor(config: TradeProcessingConfig = {}) {\n this.config = {\n maxTrades: 50000,\n strictValidation: false,\n progressCallback: () => {},\n ...config,\n };\n }\n\n /**\n * Process trade log file\n */\n async processFile(file: File): Promise<TradeProcessingResult> {\n const startTime = Date.now();\n const errors: ProcessingError[] = [];\n const warnings: string[] = [];\n\n try {\n // Validate file\n const fileValidation = CSVParser.validateCSVFile(file);\n if (!fileValidation.valid) {\n throw new Error(fileValidation.error);\n }\n\n // Configure CSV parser\n const csvParser = new CSVParser({\n maxRows: this.config.maxTrades,\n progressCallback: (progress, rowsProcessed) => {\n this.config.progressCallback({\n stage: \"parsing\",\n progress,\n rowsProcessed,\n totalRows: 0,\n errors: 0,\n validTrades: 0,\n invalidTrades: 0,\n });\n },\n });\n\n // Parse CSV with validation\n const parseResult = await csvParser.parseFileObject(\n file,\n (row, rowIndex) => this.validateRawTradeData(row, rowIndex),\n (progress) => {\n this.config.progressCallback({\n ...progress,\n validTrades: 0,\n invalidTrades: 0,\n });\n },\n );\n\n // Collect parsing errors\n errors.push(...parseResult.errors);\n warnings.push(...parseResult.warnings);\n\n // Check for required columns\n const normalizedHeaders = normalizeHeaders(parseResult.headers, TRADE_COLUMN_ALIASES);\n const missingColumns = findMissingHeaders(normalizedHeaders, REQUIRED_TRADE_COLUMNS);\n if (missingColumns.length > 0) {\n throw new Error(`Missing required columns: ${missingColumns.join(\", \")}`);\n }\n\n // Update progress for conversion stage\n this.config.progressCallback({\n stage: \"converting\",\n progress: 0,\n rowsProcessed: 0,\n totalRows: parseResult.data.length,\n errors: errors.length,\n validTrades: 0,\n invalidTrades: 0,\n });\n\n // Convert validated data to Trade objects\n const trades: Trade[] = [];\n let validTrades = 0;\n let invalidTrades = 0;\n\n for (let i = 0; i < parseResult.data.length; i++) {\n try {\n const trade = this.convertToTrade(parseResult.data[i]);\n trades.push(trade);\n validTrades++;\n } catch (error) {\n invalidTrades++;\n const errorMessage = `Trade conversion failed at row ${i + 2}: ${error instanceof Error ? error.message : String(error)}`;\n\n // Log conversion errors to console for debugging\n console.warn(`[TradeProcessor] ${errorMessage}`);\n\n const validationError: ValidationError = {\n type: \"validation\",\n message: errorMessage,\n details: { row: parseResult.data[i], rowIndex: i + 2 },\n field: \"unknown\",\n value: parseResult.data[i],\n expected: \"Valid trade data\",\n };\n errors.push(validationError);\n\n if (!this.config.strictValidation) {\n continue; // Skip invalid row in non-strict mode\n } else {\n throw error; // Fail fast in strict mode\n }\n }\n\n // Update progress\n if (i % 100 === 0 || i === parseResult.data.length - 1) {\n const progress = Math.round((i / parseResult.data.length) * 100);\n this.config.progressCallback({\n stage: \"converting\",\n progress,\n rowsProcessed: i + 1,\n totalRows: parseResult.data.length,\n errors: errors.length,\n validTrades,\n invalidTrades,\n });\n }\n }\n\n // Sort trades for consistent ordering (handles simultaneous trades)\n trades.sort((a, b) => {\n const dateCompare = new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime();\n if (dateCompare !== 0) return dateCompare;\n\n // Secondary sort by time\n const timeCompare = a.timeOpened.localeCompare(b.timeOpened);\n if (timeCompare !== 0) return timeCompare;\n\n // Tertiary sort by funds_at_close (lower first for simultaneous trades)\n return a.fundsAtClose - b.fundsAtClose;\n });\n\n // Calculate statistics\n const processingTimeMs = Date.now() - startTime;\n const strategies = Array.from(new Set(trades.map((t) => t.strategy))).sort();\n const dates = trades.map((t) => new Date(t.dateOpened));\n const dateRange = {\n start: dates.length > 0 ? new Date(Math.min(...dates.map((d) => d.getTime()))) : null,\n end: dates.length > 0 ? new Date(Math.max(...dates.map((d) => d.getTime()))) : null,\n };\n const totalPL = trades.reduce((sum, t) => sum + t.pl, 0);\n\n // Final progress update\n this.config.progressCallback({\n stage: \"completed\",\n progress: 100,\n rowsProcessed: parseResult.data.length,\n totalRows: parseResult.data.length,\n errors: errors.length,\n validTrades,\n invalidTrades,\n });\n\n return {\n trades,\n totalRows: parseResult.totalRows,\n validTrades,\n invalidTrades,\n errors,\n warnings,\n stats: {\n processingTimeMs,\n strategies,\n dateRange,\n totalPL,\n },\n };\n } catch (error) {\n const processingError: ProcessingError = {\n type: \"parsing\",\n message: `Trade processing failed: ${error instanceof Error ? error.message : String(error)}`,\n details: { fileName: file.name, fileSize: file.size },\n };\n\n return {\n trades: [],\n totalRows: 0,\n validTrades: 0,\n invalidTrades: 0,\n errors: [processingError, ...errors],\n warnings,\n stats: {\n processingTimeMs: Date.now() - startTime,\n strategies: [],\n dateRange: { start: null, end: null },\n totalPL: 0,\n },\n };\n }\n }\n\n /**\n * Validate raw trade data from CSV\n */\n private validateRawTradeData(\n row: Record<string, string>,\n rowIndex: number,\n ): Record<string, string> | null {\n try {\n // Apply column aliases to normalize variations\n const normalizedRow = { ...row };\n Object.entries(TRADE_COLUMN_ALIASES).forEach(([alias, canonical]) => {\n if (normalizedRow[alias] !== undefined) {\n normalizedRow[canonical] = normalizedRow[alias];\n delete normalizedRow[alias];\n }\n });\n\n // OptionOmega sometimes leaves strategy blank; default to Unknown so downstream stats still work\n if (!normalizedRow[\"Strategy\"] || normalizedRow[\"Strategy\"].trim() === \"\") {\n normalizedRow[\"Strategy\"] = \"Unknown\";\n }\n\n // Ensure required columns have values\n const requiredFields = [\"Date Opened\", \"P/L\", \"Strategy\"];\n for (const field of requiredFields) {\n if (!normalizedRow[field] || normalizedRow[field].trim() === \"\") {\n throw new Error(`Missing required field: ${field}`);\n }\n }\n\n // Set default values for missing optional fields\n if (!normalizedRow[\"Opening Commissions + Fees\"]) {\n normalizedRow[\"Opening Commissions + Fees\"] = \"0\";\n }\n if (!normalizedRow[\"Closing Commissions + Fees\"]) {\n normalizedRow[\"Closing Commissions + Fees\"] = \"0\";\n }\n if (!normalizedRow[\"Opening Short/Long Ratio\"]) {\n normalizedRow[\"Opening Short/Long Ratio\"] = \"0\";\n }\n\n const optionalNumericFieldsWithDefaultZero = [\n \"Opening VIX\",\n \"Closing VIX\",\n \"Gap\",\n \"Movement\",\n ] as const;\n optionalNumericFieldsWithDefaultZero.forEach((field) => {\n if (!normalizedRow[field] || normalizedRow[field].trim() === \"\") {\n normalizedRow[field] = \"0\";\n }\n });\n\n // Basic format validation (detailed validation happens in conversion)\n rawTradeDataSchema.parse(normalizedRow);\n\n return normalizedRow;\n } catch (error) {\n // Log validation errors to console for debugging\n console.warn(\n `[TradeProcessor] Row ${rowIndex + 2} validation failed:`,\n error instanceof Error ? error.message : error,\n );\n // Return null for invalid rows - they'll be counted as invalid\n return null;\n }\n }\n\n /**\n * Parse a YYYY-MM-DD date string preserving the calendar date.\n *\n * Option Omega exports dates in Eastern time. JavaScript's new Date('YYYY-MM-DD')\n * parses as UTC midnight, which when converted to local time can shift to the\n * previous day (e.g., Dec 11 UTC → Dec 10 7pm EST).\n *\n * This method creates a Date representing midnight local time on the specified\n * calendar date, so Dec 11 in the CSV becomes Dec 11 in the app regardless of timezone.\n */\n private parseDatePreservingCalendarDay(dateStr: string): Date {\n const match = dateStr.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (match) {\n const [, year, month, day] = match;\n // Create date at midnight local time - this preserves the calendar date\n return new Date(parseInt(year), parseInt(month) - 1, parseInt(day));\n }\n // Fall back to default parsing for other formats\n return new Date(dateStr);\n }\n\n /**\n * Convert validated CSV row to Trade object\n */\n private convertToTrade(rawData: Record<string, string>): Trade {\n try {\n // Parse dates preserving calendar day\n const dateOpened = this.parseDatePreservingCalendarDay(rawData[\"Date Opened\"]);\n if (isNaN(dateOpened.getTime())) {\n throw new Error(`Invalid Date Opened: ${rawData[\"Date Opened\"]}`);\n }\n\n const dateClosed = rawData[\"Date Closed\"]\n ? this.parseDatePreservingCalendarDay(rawData[\"Date Closed\"])\n : undefined;\n if (dateClosed && isNaN(dateClosed.getTime())) {\n throw new Error(`Invalid Date Closed: ${rawData[\"Date Closed\"]}`);\n }\n\n // Normalize strategy name (handle empty strings)\n const strategy = (rawData[\"Strategy\"] || \"\").trim() || \"Unknown\";\n\n // Parse numeric values with error handling and NaN handling\n const parseNumber = (\n value: string | undefined,\n fieldName: string,\n defaultValue?: number,\n ): number => {\n if (!value || value.trim() === \"\" || value.toLowerCase() === \"nan\") {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Missing required numeric field: ${fieldName}`);\n }\n\n // Remove currency symbols and commas\n const cleaned = value.replace(/[$,]/g, \"\").trim();\n const parsed = parseFloat(cleaned);\n\n if (isNaN(parsed)) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Invalid numeric value for ${fieldName}: ${value}`);\n }\n\n return parsed;\n };\n\n // Build trade object\n const rawPremiumString = (rawData[\"Premium\"] || \"\").replace(/[$,]/g, \"\").trim();\n const premiumPrecision: Trade[\"premiumPrecision\"] =\n rawPremiumString && !rawPremiumString.includes(\".\") ? \"cents\" : \"dollars\";\n\n const trade: Trade = {\n dateOpened,\n timeOpened: rawData[\"Time Opened\"] || \"00:00:00\",\n openingPrice: parseNumber(rawData[\"Opening Price\"], \"Opening Price\"),\n legs: rawData[\"Legs\"] || \"\",\n premium: parseNumber(rawData[\"Premium\"], \"Premium\"),\n premiumPrecision,\n closingPrice: rawData[\"Closing Price\"]\n ? parseNumber(rawData[\"Closing Price\"], \"Closing Price\")\n : undefined,\n dateClosed,\n timeClosed: rawData[\"Time Closed\"] || undefined,\n avgClosingCost: rawData[\"Avg. Closing Cost\"]\n ? parseNumber(rawData[\"Avg. Closing Cost\"], \"Avg. Closing Cost\")\n : undefined,\n reasonForClose: rawData[\"Reason For Close\"] || undefined,\n pl: parseNumber(rawData[\"P/L\"], \"P/L\"),\n numContracts: Math.round(parseNumber(rawData[\"No. of Contracts\"], \"No. of Contracts\")),\n fundsAtClose: parseNumber(rawData[\"Funds at Close\"], \"Funds at Close\"),\n marginReq: parseNumber(rawData[\"Margin Req.\"], \"Margin Req.\"),\n strategy,\n openingCommissionsFees: parseNumber(\n rawData[\"Opening Commissions + Fees\"],\n \"Opening Commissions\",\n 0,\n ),\n closingCommissionsFees: parseNumber(\n rawData[\"Closing Commissions + Fees\"],\n \"Closing Commissions\",\n 0,\n ),\n openingShortLongRatio: parseNumber(\n rawData[\"Opening Short/Long Ratio\"],\n \"Opening Short/Long Ratio\",\n 0,\n ),\n closingShortLongRatio: rawData[\"Closing Short/Long Ratio\"]\n ? parseNumber(rawData[\"Closing Short/Long Ratio\"], \"Closing Short/Long Ratio\")\n : undefined,\n openingVix: rawData[\"Opening VIX\"]\n ? parseNumber(rawData[\"Opening VIX\"], \"Opening VIX\")\n : undefined,\n closingVix: rawData[\"Closing VIX\"]\n ? parseNumber(rawData[\"Closing VIX\"], \"Closing VIX\")\n : undefined,\n gap: rawData[\"Gap\"] ? parseNumber(rawData[\"Gap\"], \"Gap\") : undefined,\n movement: rawData[\"Movement\"] ? parseNumber(rawData[\"Movement\"], \"Movement\") : undefined,\n maxProfit: rawData[\"Max Profit\"]\n ? parseNumber(rawData[\"Max Profit\"], \"Max Profit\")\n : undefined,\n maxLoss: rawData[\"Max Loss\"] ? parseNumber(rawData[\"Max Loss\"], \"Max Loss\") : undefined,\n };\n\n // Extract custom fields (columns not in KNOWN_TRADE_COLUMNS)\n const customFields: Record<string, number | string> = {};\n for (const [key, value] of Object.entries(rawData)) {\n if (!KNOWN_TRADE_COLUMNS.has(key) && value !== undefined && value.trim() !== \"\") {\n // Auto-detect type: try to parse as number\n const cleaned = value.replace(/[$,%]/g, \"\").trim();\n const parsed = parseFloat(cleaned);\n if (!isNaN(parsed) && isFinite(parsed)) {\n customFields[key] = parsed;\n } else {\n customFields[key] = value.trim();\n }\n }\n }\n\n // Only add customFields if there are any\n if (Object.keys(customFields).length > 0) {\n trade.customFields = customFields;\n }\n\n // Final validation with Zod schema\n const validatedTrade = tradeSchema.parse(trade);\n return validatedTrade;\n } catch (error) {\n throw new Error(\n `Trade conversion failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Process CSV content directly (for testing)\n */\n async processCSVContent(content: string): Promise<TradeProcessingResult> {\n // Create a mock File object for testing\n const blob = new Blob([content], { type: \"text/csv\" });\n const file = new File([blob], \"test.csv\", { type: \"text/csv\" });\n return this.processFile(file);\n }\n}\n"],"mappings":"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","names":[]}
|