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
package/src/tools/profiles.ts
CHANGED
|
@@ -14,12 +14,7 @@
|
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
16
|
import { getConnection, upgradeToReadWrite, downgradeToReadOnly } from "../db/connection.ts";
|
|
17
|
-
import {
|
|
18
|
-
upsertProfile,
|
|
19
|
-
getProfile,
|
|
20
|
-
listProfiles,
|
|
21
|
-
deleteProfile,
|
|
22
|
-
} from "../db/profile-schemas.ts";
|
|
17
|
+
import { upsertProfile, getProfile, listProfiles, deleteProfile } from "../db/profile-schemas.ts";
|
|
23
18
|
import { createToolOutput } from "../utils/output-formatter.ts";
|
|
24
19
|
import { withSyncedBlock } from "./middleware/sync-middleware.ts";
|
|
25
20
|
|
|
@@ -34,13 +29,13 @@ export const profileStrategySchema = z.object({
|
|
|
34
29
|
.string()
|
|
35
30
|
.describe(
|
|
36
31
|
"Option structure type: iron_condor, calendar_spread, double_calendar, vertical_spread, " +
|
|
37
|
-
"butterfly, reverse_iron_condor, short_put_spread, short_call_spread, straddle, strangle, etc."
|
|
32
|
+
"butterfly, reverse_iron_condor, short_put_spread, short_call_spread, straddle, strangle, etc.",
|
|
38
33
|
),
|
|
39
34
|
greeksBias: z
|
|
40
35
|
.string()
|
|
41
36
|
.describe(
|
|
42
37
|
"Primary greeks exposure: theta_positive, vega_negative, delta_neutral, delta_positive, " +
|
|
43
|
-
"delta_negative, gamma_scalp, etc."
|
|
38
|
+
"delta_negative, gamma_scalp, etc.",
|
|
44
39
|
),
|
|
45
40
|
thesis: z.string().default("").describe("Free-text description of the strategy thesis"),
|
|
46
41
|
legs: z
|
|
@@ -50,9 +45,12 @@ export const profileStrategySchema = z.object({
|
|
|
50
45
|
strike: z.string().describe("Strike selection: ATM, 5-delta, 30-delta, etc."),
|
|
51
46
|
expiry: z.string().describe("Expiry selection: same-day, weekly, 45-DTE, etc."),
|
|
52
47
|
quantity: z.number().describe("Quantity (positive=long, negative=short)"),
|
|
53
|
-
strikeMethod: z
|
|
48
|
+
strikeMethod: z
|
|
49
|
+
.enum(["delta", "dollar_price", "offset", "percentage"])
|
|
50
|
+
.optional()
|
|
51
|
+
.describe("How strike is selected"),
|
|
54
52
|
strikeValue: z.number().optional().describe("Numeric strike value (e.g., 25 for 25-delta)"),
|
|
55
|
-
})
|
|
53
|
+
}),
|
|
56
54
|
)
|
|
57
55
|
.default([])
|
|
58
56
|
.describe("Structured leg descriptions"),
|
|
@@ -65,32 +63,52 @@ export const profileStrategySchema = z.object({
|
|
|
65
63
|
.union([z.string(), z.number(), z.array(z.union([z.string(), z.number()]))])
|
|
66
64
|
.describe("Filter value or array for between/in operators"),
|
|
67
65
|
description: z.string().optional().describe("Human-readable description of this filter"),
|
|
68
|
-
source: z
|
|
69
|
-
|
|
66
|
+
source: z
|
|
67
|
+
.enum(["market", "execution"])
|
|
68
|
+
.optional()
|
|
69
|
+
.describe(
|
|
70
|
+
"Filter source: 'market' = testable against market data columns, 'execution' = platform-level (time windows, leg ratios). Defaults to 'market'. Execution filters are documented but skipped during validate_entry_filters analysis.",
|
|
71
|
+
),
|
|
72
|
+
}),
|
|
70
73
|
)
|
|
71
74
|
.default([])
|
|
72
|
-
.describe(
|
|
75
|
+
.describe(
|
|
76
|
+
"Entry condition filters. Tag each with source: 'market' (testable in analysis) or 'execution' (OO/platform-level, skipped in analysis).",
|
|
77
|
+
),
|
|
73
78
|
exitRules: z
|
|
74
79
|
.array(
|
|
75
80
|
z.object({
|
|
76
81
|
type: z.string().describe("Rule type: stop_loss, profit_target, time_exit, conditional"),
|
|
77
|
-
trigger: z
|
|
82
|
+
trigger: z
|
|
83
|
+
.string()
|
|
84
|
+
.describe("Trigger condition: '200% of credit', '50% of max profit', '15:00 ET'"),
|
|
78
85
|
description: z.string().optional().describe("Human-readable description"),
|
|
79
|
-
stopLossType: z
|
|
86
|
+
stopLossType: z
|
|
87
|
+
.enum(["percentage", "dollar", "sl_ratio", "debit_percentage"])
|
|
88
|
+
.optional()
|
|
89
|
+
.describe("Stop loss calculation method"),
|
|
80
90
|
stopLossValue: z.number().optional().describe("Stop loss numeric value"),
|
|
81
|
-
monitoring: z
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
monitoring: z
|
|
92
|
+
.object({
|
|
93
|
+
granularity: z
|
|
94
|
+
.enum(["intra_minute", "candle_close", "end_of_bar"])
|
|
95
|
+
.optional()
|
|
96
|
+
.describe("Price check frequency"),
|
|
97
|
+
priceSource: z.enum(["nbbo", "mid", "last"]).optional().describe("Which price to use"),
|
|
98
|
+
})
|
|
99
|
+
.optional()
|
|
100
|
+
.describe("Monitoring configuration for this rule"),
|
|
85
101
|
slippage: z.number().optional().describe("Per-rule slippage override"),
|
|
86
|
-
})
|
|
102
|
+
}),
|
|
87
103
|
)
|
|
88
104
|
.default([])
|
|
89
105
|
.describe("Exit rules and triggers"),
|
|
90
106
|
expectedRegimes: z
|
|
91
107
|
.array(z.enum(["very_low", "low", "below_avg", "above_avg", "high", "extreme"]))
|
|
92
108
|
.default([])
|
|
93
|
-
.describe(
|
|
109
|
+
.describe(
|
|
110
|
+
"VIX-based vol regimes this strategy targets. very_low=VIX<13, low=13-16, below_avg=16-20, above_avg=20-25, high=25-30, extreme=30+",
|
|
111
|
+
),
|
|
94
112
|
keyMetrics: z
|
|
95
113
|
.object({
|
|
96
114
|
expectedWinRate: z.number().optional().describe("Expected win rate (0-1)"),
|
|
@@ -103,24 +121,37 @@ export const profileStrategySchema = z.object({
|
|
|
103
121
|
.describe("Performance benchmarks and strategy-specific metrics"),
|
|
104
122
|
positionSizing: z
|
|
105
123
|
.object({
|
|
106
|
-
method: z
|
|
107
|
-
|
|
124
|
+
method: z
|
|
125
|
+
.string()
|
|
126
|
+
.describe("Sizing method: pct_of_portfolio, fixed_contracts, fixed_dollar, discretionary"),
|
|
127
|
+
allocationPct: z
|
|
128
|
+
.number()
|
|
129
|
+
.optional()
|
|
130
|
+
.describe("Portfolio allocation percentage (e.g., 2 for 2%)"),
|
|
108
131
|
maxContracts: z.number().optional().describe("Maximum contracts per trade"),
|
|
109
132
|
maxAllocationDollar: z.number().optional().describe("Maximum dollar allocation per trade"),
|
|
110
133
|
maxOpenPositions: z.number().optional().describe("Maximum concurrent open positions"),
|
|
111
134
|
description: z.string().optional().describe("Free-text sizing notes"),
|
|
112
135
|
backtestAllocationPct: z.number().optional().describe("Allocation % used in backtest"),
|
|
113
136
|
liveAllocationPct: z.number().optional().describe("Allocation % used in live portfolio"),
|
|
114
|
-
maxContractsPerTrade: z
|
|
137
|
+
maxContractsPerTrade: z
|
|
138
|
+
.number()
|
|
139
|
+
.optional()
|
|
140
|
+
.describe("Per-entry contract cap (distinct from maxContracts hard cap)"),
|
|
115
141
|
})
|
|
116
142
|
.optional()
|
|
117
|
-
.describe(
|
|
143
|
+
.describe(
|
|
144
|
+
"Position sizing rules. Per-block — same strategy in backtest vs portfolio may have different sizing.",
|
|
145
|
+
),
|
|
118
146
|
underlying: z.string().optional().describe("Underlying symbol: SPX, QQQ, etc."),
|
|
119
147
|
reEntry: z.boolean().optional().describe("Strategy supports re-entry on same day"),
|
|
120
148
|
capProfits: z.boolean().optional().describe("Profits are capped by structure"),
|
|
121
149
|
capLosses: z.boolean().optional().describe("Losses are capped by structure"),
|
|
122
150
|
requireTwoPricesPT: z.boolean().optional().describe("Profit target requires two prices"),
|
|
123
|
-
closeOnCompletion: z
|
|
151
|
+
closeOnCompletion: z
|
|
152
|
+
.boolean()
|
|
153
|
+
.optional()
|
|
154
|
+
.describe("Close entire position when any leg hits target"),
|
|
124
155
|
ignoreMarginReq: z.boolean().optional().describe("Strategy ignores standard margin requirements"),
|
|
125
156
|
});
|
|
126
157
|
|
|
@@ -130,7 +161,10 @@ export const getStrategyProfileSchema = z.object({
|
|
|
130
161
|
});
|
|
131
162
|
|
|
132
163
|
export const listProfilesSchema = z.object({
|
|
133
|
-
blockId: z
|
|
164
|
+
blockId: z
|
|
165
|
+
.string()
|
|
166
|
+
.optional()
|
|
167
|
+
.describe("Optional block ID filter. Omit to list all profiles across all blocks."),
|
|
134
168
|
});
|
|
135
169
|
|
|
136
170
|
export const deleteProfileSchema = z.object({
|
|
@@ -147,35 +181,38 @@ export const deleteProfileSchema = z.object({
|
|
|
147
181
|
*/
|
|
148
182
|
export async function handleProfileStrategy(
|
|
149
183
|
input: z.infer<typeof profileStrategySchema>,
|
|
150
|
-
baseDir: string
|
|
184
|
+
baseDir: string,
|
|
151
185
|
): Promise<ReturnType<typeof createToolOutput>> {
|
|
152
186
|
await upgradeToReadWrite(baseDir);
|
|
153
187
|
try {
|
|
154
188
|
const conn = await getConnection(baseDir);
|
|
155
|
-
const stored = await upsertProfile(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
189
|
+
const stored = await upsertProfile(
|
|
190
|
+
conn,
|
|
191
|
+
{
|
|
192
|
+
blockId: input.blockId,
|
|
193
|
+
strategyName: input.strategyName,
|
|
194
|
+
structureType: input.structureType,
|
|
195
|
+
greeksBias: input.greeksBias,
|
|
196
|
+
thesis: input.thesis,
|
|
197
|
+
legs: input.legs,
|
|
198
|
+
entryFilters: input.entryFilters,
|
|
199
|
+
exitRules: input.exitRules,
|
|
200
|
+
expectedRegimes: input.expectedRegimes,
|
|
201
|
+
keyMetrics: input.keyMetrics,
|
|
202
|
+
positionSizing: input.positionSizing,
|
|
203
|
+
underlying: input.underlying,
|
|
204
|
+
reEntry: input.reEntry,
|
|
205
|
+
capProfits: input.capProfits,
|
|
206
|
+
capLosses: input.capLosses,
|
|
207
|
+
requireTwoPricesPT: input.requireTwoPricesPT,
|
|
208
|
+
closeOnCompletion: input.closeOnCompletion,
|
|
209
|
+
ignoreMarginReq: input.ignoreMarginReq,
|
|
210
|
+
},
|
|
211
|
+
baseDir,
|
|
178
212
|
);
|
|
213
|
+
return createToolOutput(`Profile saved: ${input.strategyName} for block ${input.blockId}`, {
|
|
214
|
+
profile: stored,
|
|
215
|
+
});
|
|
179
216
|
} finally {
|
|
180
217
|
await downgradeToReadOnly(baseDir);
|
|
181
218
|
}
|
|
@@ -186,20 +223,17 @@ export async function handleProfileStrategy(
|
|
|
186
223
|
*/
|
|
187
224
|
export async function handleGetStrategyProfile(
|
|
188
225
|
input: z.infer<typeof getStrategyProfileSchema>,
|
|
189
|
-
baseDir: string
|
|
226
|
+
baseDir: string,
|
|
190
227
|
): Promise<ReturnType<typeof createToolOutput>> {
|
|
191
228
|
const conn = await getConnection(baseDir);
|
|
192
229
|
const profile = await getProfile(conn, input.blockId, input.strategyName, baseDir);
|
|
193
230
|
if (!profile) {
|
|
194
231
|
return createToolOutput(
|
|
195
232
|
`No profile found for strategy '${input.strategyName}' in block '${input.blockId}'`,
|
|
196
|
-
{ profile: null }
|
|
233
|
+
{ profile: null },
|
|
197
234
|
);
|
|
198
235
|
}
|
|
199
|
-
return createToolOutput(
|
|
200
|
-
`Profile: ${input.strategyName} in block ${input.blockId}`,
|
|
201
|
-
{ profile }
|
|
202
|
-
);
|
|
236
|
+
return createToolOutput(`Profile: ${input.strategyName} in block ${input.blockId}`, { profile });
|
|
203
237
|
}
|
|
204
238
|
|
|
205
239
|
/**
|
|
@@ -207,7 +241,7 @@ export async function handleGetStrategyProfile(
|
|
|
207
241
|
*/
|
|
208
242
|
export async function handleListProfiles(
|
|
209
243
|
input: z.infer<typeof listProfilesSchema>,
|
|
210
|
-
baseDir: string
|
|
244
|
+
baseDir: string,
|
|
211
245
|
): Promise<ReturnType<typeof createToolOutput>> {
|
|
212
246
|
const conn = await getConnection(baseDir);
|
|
213
247
|
const profiles = await listProfiles(conn, input.blockId, baseDir);
|
|
@@ -222,7 +256,7 @@ export async function handleListProfiles(
|
|
|
222
256
|
}));
|
|
223
257
|
return createToolOutput(
|
|
224
258
|
`Found ${profiles.length} profile(s)${input.blockId ? ` for block ${input.blockId}` : ""}`,
|
|
225
|
-
{ count: profiles.length, profiles: summaryRows }
|
|
259
|
+
{ count: profiles.length, profiles: summaryRows },
|
|
226
260
|
);
|
|
227
261
|
}
|
|
228
262
|
|
|
@@ -231,7 +265,7 @@ export async function handleListProfiles(
|
|
|
231
265
|
*/
|
|
232
266
|
export async function handleDeleteProfile(
|
|
233
267
|
input: z.infer<typeof deleteProfileSchema>,
|
|
234
|
-
baseDir: string
|
|
268
|
+
baseDir: string,
|
|
235
269
|
): Promise<ReturnType<typeof createToolOutput>> {
|
|
236
270
|
await upgradeToReadWrite(baseDir);
|
|
237
271
|
try {
|
|
@@ -240,12 +274,12 @@ export async function handleDeleteProfile(
|
|
|
240
274
|
if (deleted) {
|
|
241
275
|
return createToolOutput(
|
|
242
276
|
`Deleted profile: ${input.strategyName} from block ${input.blockId}`,
|
|
243
|
-
{ deleted: true }
|
|
277
|
+
{ deleted: true },
|
|
244
278
|
);
|
|
245
279
|
}
|
|
246
280
|
return createToolOutput(
|
|
247
281
|
`No profile found for strategy '${input.strategyName}' in block '${input.blockId}' — nothing to delete`,
|
|
248
|
-
{ deleted: false }
|
|
282
|
+
{ deleted: false },
|
|
249
283
|
);
|
|
250
284
|
} finally {
|
|
251
285
|
await downgradeToReadOnly(baseDir);
|
|
@@ -280,7 +314,7 @@ export function registerProfileTools(server: McpServer, baseDir: string): void {
|
|
|
280
314
|
},
|
|
281
315
|
withSyncedBlock(baseDir, async (input, ctx) => {
|
|
282
316
|
return handleProfileStrategy(input, ctx.baseDir);
|
|
283
|
-
})
|
|
317
|
+
}),
|
|
284
318
|
);
|
|
285
319
|
|
|
286
320
|
// -------------------------------------------------------------------------
|
|
@@ -296,7 +330,7 @@ export function registerProfileTools(server: McpServer, baseDir: string): void {
|
|
|
296
330
|
},
|
|
297
331
|
withSyncedBlock(baseDir, async (input, ctx) => {
|
|
298
332
|
return handleGetStrategyProfile(input, ctx.baseDir);
|
|
299
|
-
})
|
|
333
|
+
}),
|
|
300
334
|
);
|
|
301
335
|
|
|
302
336
|
// -------------------------------------------------------------------------
|
|
@@ -315,13 +349,16 @@ export function registerProfileTools(server: McpServer, baseDir: string): void {
|
|
|
315
349
|
// list_profiles has optional blockId — when provided, sync the block first;
|
|
316
350
|
// when omitted, query directly without sync (no block to validate).
|
|
317
351
|
if (input.blockId) {
|
|
318
|
-
const syncedHandler = withSyncedBlock(
|
|
319
|
-
|
|
320
|
-
|
|
352
|
+
const syncedHandler = withSyncedBlock(
|
|
353
|
+
baseDir,
|
|
354
|
+
async (syncInput: { blockId: string }, ctx) => {
|
|
355
|
+
return handleListProfiles({ blockId: syncInput.blockId }, ctx.baseDir);
|
|
356
|
+
},
|
|
357
|
+
);
|
|
321
358
|
return syncedHandler({ blockId: input.blockId });
|
|
322
359
|
}
|
|
323
360
|
return handleListProfiles(input, baseDir);
|
|
324
|
-
}
|
|
361
|
+
},
|
|
325
362
|
);
|
|
326
363
|
|
|
327
364
|
// -------------------------------------------------------------------------
|
|
@@ -337,6 +374,6 @@ export function registerProfileTools(server: McpServer, baseDir: string): void {
|
|
|
337
374
|
},
|
|
338
375
|
withSyncedBlock(baseDir, async (input, ctx) => {
|
|
339
376
|
return handleDeleteProfile(input, ctx.baseDir);
|
|
340
|
-
})
|
|
377
|
+
}),
|
|
341
378
|
);
|
|
342
379
|
}
|
|
@@ -14,21 +14,10 @@ import type { Trade } from "@tradeblocks/lib";
|
|
|
14
14
|
import { getConnection } from "../db/connection.ts";
|
|
15
15
|
import { listProfiles } from "../db/profile-schemas.ts";
|
|
16
16
|
import { filterByStrategy } from "./shared/filters.ts";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
type MarketLookupKey,
|
|
20
|
-
} from "../utils/field-timing.ts";
|
|
21
|
-
import {
|
|
22
|
-
DEFAULT_MARKET_TICKER,
|
|
23
|
-
marketTickerDateKey,
|
|
24
|
-
resolveTradeTicker,
|
|
25
|
-
} from "../utils/ticker.ts";
|
|
17
|
+
import { buildLookaheadFreeQuery, type MarketLookupKey } from "../utils/field-timing.ts";
|
|
18
|
+
import { DEFAULT_MARKET_TICKER, marketTickerDateKey, resolveTradeTicker } from "../utils/ticker.ts";
|
|
26
19
|
import { computeSliceStats, type SliceStats } from "../utils/analysis-stats.ts";
|
|
27
|
-
import {
|
|
28
|
-
upgradeToReadWrite,
|
|
29
|
-
downgradeToReadOnly,
|
|
30
|
-
getConnectionMode,
|
|
31
|
-
} from "../db/connection.ts";
|
|
20
|
+
import { upgradeToReadWrite, downgradeToReadOnly, getConnectionMode } from "../db/connection.ts";
|
|
32
21
|
import { syncAllBlocks } from "../sync/index.ts";
|
|
33
22
|
|
|
34
23
|
// =============================================================================
|
|
@@ -86,7 +75,7 @@ function resultToRecords(result: {
|
|
|
86
75
|
}
|
|
87
76
|
|
|
88
77
|
function recordsByTickerDate(
|
|
89
|
-
records: Record<string, unknown>[]
|
|
78
|
+
records: Record<string, unknown>[],
|
|
90
79
|
): Map<string, Record<string, unknown>> {
|
|
91
80
|
const mapped = new Map<string, Record<string, unknown>>();
|
|
92
81
|
for (const record of records) {
|
|
@@ -144,16 +133,12 @@ export const regimeAllocationAdvisorSchema = z.object({
|
|
|
144
133
|
blockId: z
|
|
145
134
|
.string()
|
|
146
135
|
.optional()
|
|
147
|
-
.describe(
|
|
148
|
-
"Block ID to analyze. When omitted, aggregate across all profiled strategies."
|
|
149
|
-
),
|
|
136
|
+
.describe("Block ID to analyze. When omitted, aggregate across all profiled strategies."),
|
|
150
137
|
minTrades: z
|
|
151
138
|
.number()
|
|
152
139
|
.optional()
|
|
153
140
|
.default(5)
|
|
154
|
-
.describe(
|
|
155
|
-
"Minimum trades per regime cell for reliable stats (default: 5)"
|
|
156
|
-
),
|
|
141
|
+
.describe("Minimum trades per regime cell for reliable stats (default: 5)"),
|
|
157
142
|
});
|
|
158
143
|
|
|
159
144
|
// =============================================================================
|
|
@@ -162,7 +147,7 @@ export const regimeAllocationAdvisorSchema = z.object({
|
|
|
162
147
|
|
|
163
148
|
export async function handleRegimeAllocationAdvisor(
|
|
164
149
|
input: z.infer<typeof regimeAllocationAdvisorSchema>,
|
|
165
|
-
baseDir: string
|
|
150
|
+
baseDir: string,
|
|
166
151
|
): Promise<ReturnType<typeof createToolOutput>> {
|
|
167
152
|
const minTrades = input.minTrades ?? 5;
|
|
168
153
|
const warnings: string[] = [];
|
|
@@ -177,7 +162,7 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
177
162
|
input.blockId
|
|
178
163
|
? `No strategy profiles found for block '${input.blockId}'. Use profile_strategy to create profiles first.`
|
|
179
164
|
: "No strategy profiles found. Use profile_strategy to create profiles first.",
|
|
180
|
-
{ error: "no_profiles" }
|
|
165
|
+
{ error: "no_profiles" },
|
|
181
166
|
);
|
|
182
167
|
}
|
|
183
168
|
|
|
@@ -206,7 +191,7 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
206
191
|
if (!profile.expectedRegimes || profile.expectedRegimes.length === 0) {
|
|
207
192
|
skippedNoRegimes++;
|
|
208
193
|
profileUpgradeHints.push(
|
|
209
|
-
`Strategy '${profile.strategyName}' (block: ${profile.blockId}) has no expectedRegimes. Add via profile_strategy
|
|
194
|
+
`Strategy '${profile.strategyName}' (block: ${profile.blockId}) has no expectedRegimes. Add via profile_strategy.`,
|
|
210
195
|
);
|
|
211
196
|
continue;
|
|
212
197
|
}
|
|
@@ -217,7 +202,7 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
217
202
|
block = await loadBlock(baseDir, profile.blockId);
|
|
218
203
|
} catch {
|
|
219
204
|
warnings.push(
|
|
220
|
-
`Could not load block '${profile.blockId}' for strategy '${profile.strategyName}'. Skipped
|
|
205
|
+
`Could not load block '${profile.blockId}' for strategy '${profile.strategyName}'. Skipped.`,
|
|
221
206
|
);
|
|
222
207
|
continue;
|
|
223
208
|
}
|
|
@@ -233,7 +218,7 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
233
218
|
|
|
234
219
|
if (trades.length === 0) {
|
|
235
220
|
warnings.push(
|
|
236
|
-
`No trades found for strategy '${profile.strategyName}' in block '${profile.blockId}'. Skipped
|
|
221
|
+
`No trades found for strategy '${profile.strategyName}' in block '${profile.blockId}'. Skipped.`,
|
|
237
222
|
);
|
|
238
223
|
continue;
|
|
239
224
|
}
|
|
@@ -267,14 +252,14 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
267
252
|
if (matched.length === 0) {
|
|
268
253
|
skippedNoMarket++;
|
|
269
254
|
warnings.push(
|
|
270
|
-
`No market data matched for strategy '${profile.strategyName}' (${trades.length} trades). Import and enrich market data first
|
|
255
|
+
`No market data matched for strategy '${profile.strategyName}' (${trades.length} trades). Import and enrich market data first.`,
|
|
271
256
|
);
|
|
272
257
|
continue;
|
|
273
258
|
}
|
|
274
259
|
|
|
275
260
|
if (unmatchedCount > 0) {
|
|
276
261
|
warnings.push(
|
|
277
|
-
`Strategy '${profile.strategyName}': ${unmatchedCount} of ${trades.length} trades had no market data match
|
|
262
|
+
`Strategy '${profile.strategyName}': ${unmatchedCount} of ${trades.length} trades had no market data match.`,
|
|
278
263
|
);
|
|
279
264
|
}
|
|
280
265
|
|
|
@@ -297,9 +282,7 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
297
282
|
}
|
|
298
283
|
|
|
299
284
|
// Build per-regime comparison
|
|
300
|
-
const expectedSet = new Set(
|
|
301
|
-
profile.expectedRegimes.map((r) => r.toLowerCase())
|
|
302
|
-
);
|
|
285
|
+
const expectedSet = new Set(profile.expectedRegimes.map((r) => r.toLowerCase()));
|
|
303
286
|
const regimePerformance: Record<string, RegimeCell> = {};
|
|
304
287
|
|
|
305
288
|
for (const [label, pls] of Object.entries(regimePls)) {
|
|
@@ -345,8 +328,7 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
345
328
|
|
|
346
329
|
// Allocation from position sizing
|
|
347
330
|
const allocationPct =
|
|
348
|
-
profile.positionSizing?.liveAllocationPct ??
|
|
349
|
-
profile.positionSizing?.allocationPct;
|
|
331
|
+
profile.positionSizing?.liveAllocationPct ?? profile.positionSizing?.allocationPct;
|
|
350
332
|
|
|
351
333
|
strategies.push({
|
|
352
334
|
strategyName: profile.strategyName,
|
|
@@ -362,7 +344,7 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
362
344
|
});
|
|
363
345
|
} catch (err) {
|
|
364
346
|
warnings.push(
|
|
365
|
-
`Error processing strategy '${profile.strategyName}' (block: ${profile.blockId}): ${(err as Error).message}
|
|
347
|
+
`Error processing strategy '${profile.strategyName}' (block: ${profile.blockId}): ${(err as Error).message}`,
|
|
366
348
|
);
|
|
367
349
|
}
|
|
368
350
|
}
|
|
@@ -400,12 +382,8 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
400
382
|
const summaryText =
|
|
401
383
|
`Regime allocation advisor: ${strategies.length}/${profiles.length} strategies analyzed. ` +
|
|
402
384
|
`${allThesisViolations.length} thesis violation(s), ${allHiddenEdges.length} hidden edge(s). ` +
|
|
403
|
-
(skippedNoRegimes > 0
|
|
404
|
-
|
|
405
|
-
: "") +
|
|
406
|
-
(skippedNoMarket > 0
|
|
407
|
-
? `${skippedNoMarket} skipped (no market data). `
|
|
408
|
-
: "");
|
|
385
|
+
(skippedNoRegimes > 0 ? `${skippedNoRegimes} skipped (no expectedRegimes). ` : "") +
|
|
386
|
+
(skippedNoMarket > 0 ? `${skippedNoMarket} skipped (no market data). ` : "");
|
|
409
387
|
|
|
410
388
|
return createToolOutput(summaryText, {
|
|
411
389
|
strategies,
|
|
@@ -420,10 +398,7 @@ export async function handleRegimeAllocationAdvisor(
|
|
|
420
398
|
// Registration
|
|
421
399
|
// =============================================================================
|
|
422
400
|
|
|
423
|
-
export function registerRegimeAdvisorTools(
|
|
424
|
-
server: McpServer,
|
|
425
|
-
baseDir: string
|
|
426
|
-
): void {
|
|
401
|
+
export function registerRegimeAdvisorTools(server: McpServer, baseDir: string): void {
|
|
427
402
|
server.registerTool(
|
|
428
403
|
"regime_allocation_advisor",
|
|
429
404
|
{
|
|
@@ -450,6 +425,6 @@ export function registerRegimeAdvisorTools(
|
|
|
450
425
|
}
|
|
451
426
|
}
|
|
452
427
|
return handleRegimeAllocationAdvisor(input, baseDir);
|
|
453
|
-
}
|
|
428
|
+
},
|
|
454
429
|
);
|
|
455
430
|
}
|