@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/README.md +128 -0
- package/bun.lock +218 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +667 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/index.ts +828 -0
- package/tsconfig.json +22 -0
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
|
+
});
|