@ebowwa/quant-mcp 1.0.0

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/src/index.ts ADDED
@@ -0,0 +1,828 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @ebowwa/quant-mcp - Quantitative Trading MCP Server
4
+ *
5
+ * Multi-market quantitative analysis tools for AI trading:
6
+ * - Prediction Markets: Kelly criterion, AMM math, LMSR, arbitrage
7
+ * - Technical Indicators: RSI, MACD, Bollinger, ATR, etc.
8
+ * - Risk Management: VaR, Sharpe ratio, drawdown analysis
9
+ * - Statistics: Correlation, regression, time series
10
+ */
11
+
12
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
13
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
14
+ import {
15
+ CallToolRequestSchema,
16
+ ListToolsRequestSchema,
17
+ } from "@modelcontextprotocol/sdk/types.js";
18
+ import { z } from "zod";
19
+
20
+ // Import quant tools
21
+ import {
22
+ // Prediction markets
23
+ kellyCriterion,
24
+ fractionalKelly,
25
+ probToDecimalOdds,
26
+ probToAmericanOdds,
27
+ decimalOddsToProb,
28
+ americanOddsToProb,
29
+ ammBuyCost,
30
+ ammSharesReceived,
31
+ ammPriceImpact,
32
+ ammImpermanentLoss,
33
+ lmsrPrice,
34
+ lmsrBuyCost,
35
+ detectArbitrage,
36
+ brierScore,
37
+ logLoss,
38
+ calculateCalibration,
39
+ hasPositiveEV,
40
+ calculateEdge,
41
+ calculatePnL,
42
+ calculateUnrealizedPnL,
43
+
44
+ // Technical indicators
45
+ sma,
46
+ ema,
47
+ wma,
48
+ rsi,
49
+ macd,
50
+ stochastic,
51
+ bollingerBands,
52
+ atr,
53
+ adx,
54
+ pivotPoints,
55
+ fibonacciRetracement,
56
+
57
+ // Risk management
58
+ fixedFractionalSize,
59
+ historicalVaR,
60
+ parametricVaR,
61
+ calculateVaR,
62
+ calculateDrawdown,
63
+ sharpeRatio,
64
+ sortinoRatio,
65
+ calmarRatio,
66
+ beta,
67
+ alpha,
68
+
69
+ // Statistics
70
+ distributionStats,
71
+ pearsonCorrelation,
72
+ linearRegression,
73
+ autocorrelation,
74
+
75
+ // Utils
76
+ mean,
77
+ stdDev,
78
+ variance,
79
+ } from "@ebowwa/quant";
80
+
81
+ // ==============
82
+ // Tool Definitions
83
+ // ==============
84
+
85
+ const tools = [
86
+ // ===================
87
+ // PREDICTION MARKETS
88
+ // ===================
89
+ {
90
+ name: "kelly_criterion",
91
+ description: "Calculate optimal bet size using Kelly criterion for binary prediction markets. Returns Kelly fraction, half-Kelly, quarter-Kelly, and position sizes.",
92
+ inputSchema: {
93
+ type: "object",
94
+ properties: {
95
+ yourProbability: {
96
+ type: "number",
97
+ description: "Your estimated probability of winning (0-1)",
98
+ minimum: 0,
99
+ maximum: 1,
100
+ },
101
+ marketPrice: {
102
+ type: "number",
103
+ description: "Current market price to buy shares (0-1)",
104
+ minimum: 0,
105
+ maximum: 1,
106
+ },
107
+ bankroll: {
108
+ type: "number",
109
+ description: "Your total bankroll in currency units",
110
+ minimum: 0,
111
+ },
112
+ },
113
+ required: ["yourProbability", "marketPrice", "bankroll"],
114
+ },
115
+ },
116
+ {
117
+ name: "convert_odds",
118
+ description: "Convert between probability, decimal odds, and American odds formats",
119
+ inputSchema: {
120
+ type: "object",
121
+ properties: {
122
+ value: { type: "number", description: "Value to convert" },
123
+ fromFormat: {
124
+ type: "string",
125
+ enum: ["probability", "decimal", "american"],
126
+ description: "Input format",
127
+ },
128
+ },
129
+ required: ["value", "fromFormat"],
130
+ },
131
+ },
132
+ {
133
+ name: "amm_calculate_cost",
134
+ description: "Calculate cost to buy shares from a constant-product AMM (like Polymarket). Returns cost in quote currency.",
135
+ inputSchema: {
136
+ type: "object",
137
+ properties: {
138
+ poolYes: { type: "number", description: "YES pool size" },
139
+ poolNo: { type: "number", description: "NO pool size" },
140
+ outcome: { type: "string", enum: ["yes", "no"], description: "Outcome to buy" },
141
+ shares: { type: "number", description: "Number of shares to buy", minimum: 0 },
142
+ },
143
+ required: ["poolYes", "poolNo", "outcome", "shares"],
144
+ },
145
+ },
146
+ {
147
+ name: "amm_price_impact",
148
+ description: "Calculate price impact and slippage for a trade on a constant-product AMM",
149
+ inputSchema: {
150
+ type: "object",
151
+ properties: {
152
+ poolYes: { type: "number", description: "YES pool size" },
153
+ poolNo: { type: "number", description: "NO pool size" },
154
+ outcome: { type: "string", enum: ["yes", "no"], description: "Outcome to buy" },
155
+ shares: { type: "number", description: "Number of shares to buy", minimum: 0 },
156
+ },
157
+ required: ["poolYes", "poolNo", "outcome", "shares"],
158
+ },
159
+ },
160
+ {
161
+ name: "lmsr_calculate",
162
+ description: "Calculate price and cost using LMSR (Logarithmic Market Scoring Rule) for prediction markets",
163
+ inputSchema: {
164
+ type: "object",
165
+ properties: {
166
+ yesShares: { type: "number", description: "Current YES shares outstanding" },
167
+ noShares: { type: "number", description: "Current NO shares outstanding" },
168
+ liquidityParam: { type: "number", description: "Liquidity parameter (b)", minimum: 0 },
169
+ operation: {
170
+ type: "string",
171
+ enum: ["price", "cost"],
172
+ description: "Calculate price or cost to buy shares",
173
+ },
174
+ outcome: { type: "string", enum: ["yes", "no"], description: "Outcome" },
175
+ sharesToBuy: { type: "number", description: "Shares to buy (for cost operation)" },
176
+ },
177
+ required: ["yesShares", "noShares", "liquidityParam", "operation", "outcome"],
178
+ },
179
+ },
180
+ {
181
+ name: "detect_arbitrage",
182
+ description: "Detect arbitrage opportunities in prediction markets. Returns profit if YES + NO prices < 1.",
183
+ inputSchema: {
184
+ type: "object",
185
+ properties: {
186
+ yesPrice: { type: "number", description: "YES share price (0-1)", minimum: 0, maximum: 1 },
187
+ noPrice: { type: "number", description: "NO share price (0-1)", minimum: 0, maximum: 1 },
188
+ },
189
+ required: ["yesPrice", "noPrice"],
190
+ },
191
+ },
192
+ {
193
+ name: "calculate_edge",
194
+ description: "Calculate your edge (advantage) in a prediction market bet",
195
+ inputSchema: {
196
+ type: "object",
197
+ properties: {
198
+ yourProbability: { type: "number", description: "Your probability estimate (0-1)" },
199
+ marketPrice: { type: "number", description: "Market price (0-1)" },
200
+ },
201
+ required: ["yourProbability", "marketPrice"],
202
+ },
203
+ },
204
+ {
205
+ name: "brier_score",
206
+ description: "Calculate Brier score to measure accuracy of probability predictions (lower is better, 0=perfect)",
207
+ inputSchema: {
208
+ type: "object",
209
+ properties: {
210
+ predictions: {
211
+ type: "array",
212
+ items: {
213
+ type: "object",
214
+ properties: {
215
+ predicted: { type: "number", description: "Predicted probability (0-1)" },
216
+ actual: { type: "number", description: "Actual outcome (0 or 1)" },
217
+ },
218
+ required: ["predicted", "actual"],
219
+ },
220
+ description: "Array of prediction/outcome pairs",
221
+ },
222
+ },
223
+ required: ["predictions"],
224
+ },
225
+ },
226
+
227
+ // ===================
228
+ // TECHNICAL INDICATORS
229
+ // ===================
230
+ {
231
+ name: "calculate_sma",
232
+ description: "Calculate Simple Moving Average for price data",
233
+ inputSchema: {
234
+ type: "object",
235
+ properties: {
236
+ prices: { type: "array", items: { type: "number" }, description: "Array of prices" },
237
+ period: { type: "number", description: "Period for SMA", minimum: 1 },
238
+ },
239
+ required: ["prices", "period"],
240
+ },
241
+ },
242
+ {
243
+ name: "calculate_ema",
244
+ description: "Calculate Exponential Moving Average for price data",
245
+ inputSchema: {
246
+ type: "object",
247
+ properties: {
248
+ prices: { type: "array", items: { type: "number" }, description: "Array of prices" },
249
+ period: { type: "number", description: "Period for EMA", minimum: 1 },
250
+ },
251
+ required: ["prices", "period"],
252
+ },
253
+ },
254
+ {
255
+ name: "calculate_rsi",
256
+ description: "Calculate Relative Strength Index (RSI) momentum indicator (0-100)",
257
+ inputSchema: {
258
+ type: "object",
259
+ properties: {
260
+ prices: { type: "array", items: { type: "number" }, description: "Array of prices" },
261
+ period: { type: "number", description: "Period for RSI (default 14)", default: 14 },
262
+ },
263
+ required: ["prices"],
264
+ },
265
+ },
266
+ {
267
+ name: "calculate_macd",
268
+ description: "Calculate MACD (Moving Average Convergence Divergence) indicator",
269
+ inputSchema: {
270
+ type: "object",
271
+ properties: {
272
+ prices: { type: "array", items: { type: "number" }, description: "Array of prices" },
273
+ fastPeriod: { type: "number", description: "Fast EMA period (default 12)", default: 12 },
274
+ slowPeriod: { type: "number", description: "Slow EMA period (default 26)", default: 26 },
275
+ signalPeriod: { type: "number", description: "Signal line period (default 9)", default: 9 },
276
+ },
277
+ required: ["prices"],
278
+ },
279
+ },
280
+ {
281
+ name: "calculate_bollinger_bands",
282
+ description: "Calculate Bollinger Bands volatility indicator",
283
+ inputSchema: {
284
+ type: "object",
285
+ properties: {
286
+ prices: { type: "array", items: { type: "number" }, description: "Array of prices" },
287
+ period: { type: "number", description: "Period (default 20)", default: 20 },
288
+ stdDevMultiplier: { type: "number", description: "Standard deviation multiplier (default 2)", default: 2 },
289
+ },
290
+ required: ["prices"],
291
+ },
292
+ },
293
+ {
294
+ name: "calculate_atr",
295
+ description: "Calculate Average True Range (ATR) volatility indicator",
296
+ inputSchema: {
297
+ type: "object",
298
+ properties: {
299
+ high: { type: "array", items: { type: "number" }, description: "High prices" },
300
+ low: { type: "array", items: { type: "number" }, description: "Low prices" },
301
+ close: { type: "array", items: { type: "number" }, description: "Close prices" },
302
+ period: { type: "number", description: "Period (default 14)", default: 14 },
303
+ },
304
+ required: ["high", "low", "close"],
305
+ },
306
+ },
307
+ {
308
+ name: "calculate_stochastic",
309
+ description: "Calculate Stochastic Oscillator (%K and %D)",
310
+ inputSchema: {
311
+ type: "object",
312
+ properties: {
313
+ high: { type: "array", items: { type: "number" }, description: "High prices" },
314
+ low: { type: "array", items: { type: "number" }, description: "Low prices" },
315
+ close: { type: "array", items: { type: "number" }, description: "Close prices" },
316
+ kPeriod: { type: "number", description: "%K period (default 14)", default: 14 },
317
+ dPeriod: { type: "number", description: "%D period (default 3)", default: 3 },
318
+ },
319
+ required: ["high", "low", "close"],
320
+ },
321
+ },
322
+ {
323
+ name: "calculate_pivot_points",
324
+ description: "Calculate classic pivot points and support/resistance levels",
325
+ inputSchema: {
326
+ type: "object",
327
+ properties: {
328
+ high: { type: "number", description: "Period high price" },
329
+ low: { type: "number", description: "Period low price" },
330
+ close: { type: "number", description: "Period close price" },
331
+ },
332
+ required: ["high", "low", "close"],
333
+ },
334
+ },
335
+ {
336
+ name: "calculate_fibonacci_retracement",
337
+ description: "Calculate Fibonacci retracement levels between swing high and low",
338
+ inputSchema: {
339
+ type: "object",
340
+ properties: {
341
+ swingHigh: { type: "number", description: "Swing high price" },
342
+ swingLow: { type: "number", description: "Swing low price" },
343
+ },
344
+ required: ["swingHigh", "swingLow"],
345
+ },
346
+ },
347
+
348
+ // ===================
349
+ // RISK MANAGEMENT
350
+ // ===================
351
+ {
352
+ name: "position_size_fixed_fractional",
353
+ description: "Calculate position size using fixed fractional risk management",
354
+ inputSchema: {
355
+ type: "object",
356
+ properties: {
357
+ capital: { type: "number", description: "Total capital", minimum: 0 },
358
+ riskPercent: { type: "number", description: "Percent of capital to risk (e.g., 0.02 for 2%)", minimum: 0, maximum: 1 },
359
+ entryPrice: { type: "number", description: "Entry price", minimum: 0 },
360
+ stopLoss: { type: "number", description: "Stop loss price", minimum: 0 },
361
+ },
362
+ required: ["capital", "riskPercent", "entryPrice", "stopLoss"],
363
+ },
364
+ },
365
+ {
366
+ name: "calculate_var",
367
+ description: "Calculate Value at Risk (VaR) and Expected Shortfall (CVaR) for a returns series",
368
+ inputSchema: {
369
+ type: "object",
370
+ properties: {
371
+ returns: { type: "array", items: { type: "number" }, description: "Array of returns" },
372
+ confidenceLevel: { type: "number", description: "Confidence level (default 0.95)", default: 0.95 },
373
+ },
374
+ required: ["returns"],
375
+ },
376
+ },
377
+ {
378
+ name: "calculate_drawdown",
379
+ description: "Calculate maximum drawdown and drawdown analysis for an equity curve",
380
+ inputSchema: {
381
+ type: "object",
382
+ properties: {
383
+ equityCurve: { type: "array", items: { type: "number" }, description: "Equity curve values over time" },
384
+ },
385
+ required: ["equityCurve"],
386
+ },
387
+ },
388
+ {
389
+ name: "calculate_sharpe_ratio",
390
+ description: "Calculate Sharpe ratio for risk-adjusted returns",
391
+ inputSchema: {
392
+ type: "object",
393
+ properties: {
394
+ returns: { type: "array", items: { type: "number" }, description: "Array of returns" },
395
+ riskFreeRate: { type: "number", description: "Annual risk-free rate (default 0.04)", default: 0.04 },
396
+ periodsPerYear: { type: "number", description: "Trading periods per year (default 252)", default: 252 },
397
+ },
398
+ required: ["returns"],
399
+ },
400
+ },
401
+ {
402
+ name: "calculate_sortino_ratio",
403
+ description: "Calculate Sortino ratio (only penalizes downside volatility)",
404
+ inputSchema: {
405
+ type: "object",
406
+ properties: {
407
+ returns: { type: "array", items: { type: "number" }, description: "Array of returns" },
408
+ riskFreeRate: { type: "number", description: "Annual risk-free rate (default 0.04)", default: 0.04 },
409
+ periodsPerYear: { type: "number", description: "Trading periods per year (default 252)", default: 252 },
410
+ },
411
+ required: ["returns"],
412
+ },
413
+ },
414
+ {
415
+ name: "calculate_beta_alpha",
416
+ description: "Calculate beta (market sensitivity) and alpha (excess return) vs benchmark",
417
+ inputSchema: {
418
+ type: "object",
419
+ properties: {
420
+ assetReturns: { type: "array", items: { type: "number" }, description: "Asset returns" },
421
+ marketReturns: { type: "array", items: { type: "number" }, description: "Market/benchmark returns" },
422
+ riskFreeRate: { type: "number", description: "Annual risk-free rate (default 0.04)", default: 0.04 },
423
+ },
424
+ required: ["assetReturns", "marketReturns"],
425
+ },
426
+ },
427
+
428
+ // ===================
429
+ // STATISTICS
430
+ // ===================
431
+ {
432
+ name: "distribution_statistics",
433
+ description: "Calculate comprehensive distribution statistics (mean, median, stdDev, skewness, kurtosis, quartiles)",
434
+ inputSchema: {
435
+ type: "object",
436
+ properties: {
437
+ data: { type: "array", items: { type: "number" }, description: "Data array" },
438
+ },
439
+ required: ["data"],
440
+ },
441
+ },
442
+ {
443
+ name: "correlation",
444
+ description: "Calculate Pearson correlation coefficient between two series",
445
+ inputSchema: {
446
+ type: "object",
447
+ properties: {
448
+ x: { type: "array", items: { type: "number" }, description: "First data series" },
449
+ y: { type: "array", items: { type: "number" }, description: "Second data series" },
450
+ },
451
+ required: ["x", "y"],
452
+ },
453
+ },
454
+ {
455
+ name: "linear_regression",
456
+ description: "Perform linear regression analysis",
457
+ inputSchema: {
458
+ type: "object",
459
+ properties: {
460
+ x: { type: "array", items: { type: "number" }, description: "Independent variable" },
461
+ y: { type: "array", items: { type: "number" }, description: "Dependent variable" },
462
+ },
463
+ required: ["x", "y"],
464
+ },
465
+ },
466
+ {
467
+ name: "autocorrelation",
468
+ description: "Calculate autocorrelation function for time series analysis",
469
+ inputSchema: {
470
+ type: "object",
471
+ properties: {
472
+ data: { type: "array", items: { type: "number" }, description: "Time series data" },
473
+ maxLag: { type: "number", description: "Maximum lag to calculate (default 10)", default: 10 },
474
+ },
475
+ required: ["data"],
476
+ },
477
+ },
478
+ ];
479
+
480
+ // ==============
481
+ // MCP Server
482
+ // ==============
483
+
484
+ const server = new Server(
485
+ {
486
+ name: "@ebowwa/quant-mcp",
487
+ version: "1.0.0",
488
+ },
489
+ {
490
+ capabilities: {
491
+ tools: {},
492
+ },
493
+ }
494
+ );
495
+
496
+ // List tools handler
497
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
498
+ return { tools };
499
+ });
500
+
501
+ // Call tool handler
502
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
503
+ const { name, arguments: args } = request.params;
504
+
505
+ try {
506
+ let result: unknown;
507
+
508
+ switch (name) {
509
+ // Prediction Markets
510
+ case "kelly_criterion": {
511
+ const { yourProbability, marketPrice, bankroll } = args as {
512
+ yourProbability: number;
513
+ marketPrice: number;
514
+ bankroll: number;
515
+ };
516
+ result = kellyCriterion(yourProbability, marketPrice, bankroll);
517
+ break;
518
+ }
519
+
520
+ case "convert_odds": {
521
+ const { value, fromFormat } = args as { value: number; fromFormat: string };
522
+ if (fromFormat === "probability") {
523
+ result = {
524
+ probability: value,
525
+ decimal: probToDecimalOdds(value),
526
+ american: probToAmericanOdds(value),
527
+ };
528
+ } else if (fromFormat === "decimal") {
529
+ result = {
530
+ probability: decimalOddsToProb(value),
531
+ decimal: value,
532
+ american: probToAmericanOdds(decimalOddsToProb(value)),
533
+ };
534
+ } else {
535
+ const prob = americanOddsToProb(value);
536
+ result = {
537
+ probability: prob,
538
+ decimal: probToDecimalOdds(prob),
539
+ american: value,
540
+ };
541
+ }
542
+ break;
543
+ }
544
+
545
+ case "amm_calculate_cost": {
546
+ const { poolYes, poolNo, outcome, shares } = args as {
547
+ poolYes: number;
548
+ poolNo: number;
549
+ outcome: "yes" | "no";
550
+ shares: number;
551
+ };
552
+ const state = { poolYes, poolNo, k: poolYes * poolNo, lpTokenSupply: 1000, fee: 0 };
553
+ const cost = ammBuyCost(state, outcome, shares);
554
+ const sharesOut = ammSharesReceived(state, outcome, cost);
555
+ result = {
556
+ cost,
557
+ shares: sharesOut,
558
+ avgPrice: cost / sharesOut,
559
+ effectivePrice: cost / shares,
560
+ };
561
+ break;
562
+ }
563
+
564
+ case "amm_price_impact": {
565
+ const { poolYes, poolNo, outcome, shares } = args as {
566
+ poolYes: number;
567
+ poolNo: number;
568
+ outcome: "yes" | "no";
569
+ shares: number;
570
+ };
571
+ const state = { poolYes, poolNo, k: poolYes * poolNo, lpTokenSupply: 1000, fee: 0 };
572
+ result = ammPriceImpact(state, outcome, shares);
573
+ break;
574
+ }
575
+
576
+ case "lmsr_calculate": {
577
+ const { yesShares, noShares, liquidityParam, operation, outcome, sharesToBuy } = args as {
578
+ yesShares: number;
579
+ noShares: number;
580
+ liquidityParam: number;
581
+ operation: string;
582
+ outcome: "yes" | "no";
583
+ sharesToBuy?: number;
584
+ };
585
+ const state = { yesShares, noShares, b: liquidityParam };
586
+ if (operation === "price") {
587
+ result = {
588
+ yesPrice: lmsrPrice(state, "yes"),
589
+ noPrice: lmsrPrice(state, "no"),
590
+ };
591
+ } else {
592
+ const cost = sharesToBuy ? lmsrBuyCost(state, outcome, sharesToBuy) : null;
593
+ result = {
594
+ cost,
595
+ price: lmsrPrice(state, outcome),
596
+ };
597
+ }
598
+ break;
599
+ }
600
+
601
+ case "detect_arbitrage": {
602
+ const { yesPrice, noPrice } = args as { yesPrice: number; noPrice: number };
603
+ result = detectArbitrage(yesPrice, noPrice);
604
+ break;
605
+ }
606
+
607
+ case "calculate_edge": {
608
+ const { yourProbability, marketPrice } = args as {
609
+ yourProbability: number;
610
+ marketPrice: number;
611
+ };
612
+ result = {
613
+ edge: calculateEdge(yourProbability, marketPrice),
614
+ hasPositiveEV: hasPositiveEV(yourProbability, marketPrice),
615
+ yourProbability,
616
+ marketPrice,
617
+ };
618
+ break;
619
+ }
620
+
621
+ case "brier_score": {
622
+ const { predictions } = args as {
623
+ predictions: Array<{ predicted: number; actual: number }>;
624
+ };
625
+ result = {
626
+ brierScore: brierScore(predictions),
627
+ logLoss: logLoss(predictions),
628
+ };
629
+ break;
630
+ }
631
+
632
+ // Technical Indicators
633
+ case "calculate_sma": {
634
+ const { prices, period } = args as { prices: number[]; period: number };
635
+ result = { sma: sma(prices, period) };
636
+ break;
637
+ }
638
+
639
+ case "calculate_ema": {
640
+ const { prices, period } = args as { prices: number[]; period: number };
641
+ result = { ema: ema(prices, period) };
642
+ break;
643
+ }
644
+
645
+ case "calculate_rsi": {
646
+ const { prices, period = 14 } = args as { prices: number[]; period?: number };
647
+ result = { rsi: rsi(prices, period) };
648
+ break;
649
+ }
650
+
651
+ case "calculate_macd": {
652
+ const { prices, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9 } = args as {
653
+ prices: number[];
654
+ fastPeriod?: number;
655
+ slowPeriod?: number;
656
+ signalPeriod?: number;
657
+ };
658
+ result = macd(prices, fastPeriod, slowPeriod, signalPeriod);
659
+ break;
660
+ }
661
+
662
+ case "calculate_bollinger_bands": {
663
+ const { prices, period = 20, stdDevMultiplier = 2 } = args as {
664
+ prices: number[];
665
+ period?: number;
666
+ stdDevMultiplier?: number;
667
+ };
668
+ result = bollingerBands(prices, period, stdDevMultiplier);
669
+ break;
670
+ }
671
+
672
+ case "calculate_atr": {
673
+ const { high, low, close, period = 14 } = args as {
674
+ high: number[];
675
+ low: number[];
676
+ close: number[];
677
+ period?: number;
678
+ };
679
+ result = atr(high, low, close, period);
680
+ break;
681
+ }
682
+
683
+ case "calculate_stochastic": {
684
+ const { high, low, close, kPeriod = 14, dPeriod = 3 } = args as {
685
+ high: number[];
686
+ low: number[];
687
+ close: number[];
688
+ kPeriod?: number;
689
+ dPeriod?: number;
690
+ };
691
+ result = stochastic(high, low, close, kPeriod, dPeriod);
692
+ break;
693
+ }
694
+
695
+ case "calculate_pivot_points": {
696
+ const { high, low, close } = args as { high: number; low: number; close: number };
697
+ result = pivotPoints(high, low, close);
698
+ break;
699
+ }
700
+
701
+ case "calculate_fibonacci_retracement": {
702
+ const { swingHigh, swingLow } = args as { swingHigh: number; swingLow: number };
703
+ result = fibonacciRetracement(swingHigh, swingLow);
704
+ break;
705
+ }
706
+
707
+ // Risk Management
708
+ case "position_size_fixed_fractional": {
709
+ const { capital, riskPercent, entryPrice, stopLoss } = args as {
710
+ capital: number;
711
+ riskPercent: number;
712
+ entryPrice: number;
713
+ stopLoss: number;
714
+ };
715
+ result = fixedFractionalSize(capital, riskPercent, entryPrice, stopLoss);
716
+ break;
717
+ }
718
+
719
+ case "calculate_var": {
720
+ const { returns, confidenceLevel = 0.95 } = args as {
721
+ returns: number[];
722
+ confidenceLevel?: number;
723
+ };
724
+ result = calculateVaR(returns, { confidenceLevel });
725
+ break;
726
+ }
727
+
728
+ case "calculate_drawdown": {
729
+ const { equityCurve } = args as { equityCurve: number[] };
730
+ result = calculateDrawdown(equityCurve);
731
+ break;
732
+ }
733
+
734
+ case "calculate_sharpe_ratio": {
735
+ const { returns, riskFreeRate = 0.04, periodsPerYear = 252 } = args as {
736
+ returns: number[];
737
+ riskFreeRate?: number;
738
+ periodsPerYear?: number;
739
+ };
740
+ result = { sharpeRatio: sharpeRatio(returns, riskFreeRate, periodsPerYear) };
741
+ break;
742
+ }
743
+
744
+ case "calculate_sortino_ratio": {
745
+ const { returns, riskFreeRate = 0.04, periodsPerYear = 252 } = args as {
746
+ returns: number[];
747
+ riskFreeRate?: number;
748
+ periodsPerYear?: number;
749
+ };
750
+ result = { sortinoRatio: sortinoRatio(returns, riskFreeRate, periodsPerYear) };
751
+ break;
752
+ }
753
+
754
+ case "calculate_beta_alpha": {
755
+ const { assetReturns, marketReturns, riskFreeRate = 0.04 } = args as {
756
+ assetReturns: number[];
757
+ marketReturns: number[];
758
+ riskFreeRate?: number;
759
+ };
760
+ result = {
761
+ beta: beta(assetReturns, marketReturns),
762
+ alpha: alpha(assetReturns, marketReturns, riskFreeRate),
763
+ };
764
+ break;
765
+ }
766
+
767
+ // Statistics
768
+ case "distribution_statistics": {
769
+ const { data } = args as { data: number[] };
770
+ result = distributionStats(data);
771
+ break;
772
+ }
773
+
774
+ case "correlation": {
775
+ const { x, y } = args as { x: number[]; y: number[] };
776
+ result = { correlation: pearsonCorrelation(x, y) };
777
+ break;
778
+ }
779
+
780
+ case "linear_regression": {
781
+ const { x, y } = args as { x: number[]; y: number[] };
782
+ result = linearRegression(x, y);
783
+ break;
784
+ }
785
+
786
+ case "autocorrelation": {
787
+ const { data, maxLag = 10 } = args as { data: number[]; maxLag?: number };
788
+ result = { acf: autocorrelation(data, maxLag) };
789
+ break;
790
+ }
791
+
792
+ default:
793
+ throw new Error(`Unknown tool: ${name}`);
794
+ }
795
+
796
+ return {
797
+ content: [
798
+ {
799
+ type: "text",
800
+ text: JSON.stringify(result, null, 2),
801
+ },
802
+ ],
803
+ };
804
+ } catch (error) {
805
+ const errorMessage = error instanceof Error ? error.message : String(error);
806
+ return {
807
+ content: [
808
+ {
809
+ type: "text",
810
+ text: JSON.stringify({ error: errorMessage }),
811
+ },
812
+ ],
813
+ isError: true,
814
+ };
815
+ }
816
+ });
817
+
818
+ // Start server
819
+ async function main() {
820
+ const transport = new StdioServerTransport();
821
+ await server.connect(transport);
822
+ console.error("Quant MCP server running on stdio");
823
+ }
824
+
825
+ main().catch((error) => {
826
+ console.error("Fatal error:", error);
827
+ process.exit(1);
828
+ });