fixparser-plugin-mcp 9.1.7-c415bb75 → 9.1.7-c6228661
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/build/cjs/MCPLocal.js +422 -10
- package/build/cjs/MCPLocal.js.map +4 -4
- package/build/cjs/MCPRemote.js +422 -66
- package/build/cjs/MCPRemote.js.map +4 -4
- package/build/cjs/index.js +422 -66
- package/build/cjs/index.js.map +4 -4
- package/build/esm/MCPLocal.mjs +422 -10
- package/build/esm/MCPLocal.mjs.map +4 -4
- package/build/esm/MCPRemote.mjs +422 -66
- package/build/esm/MCPRemote.mjs.map +4 -4
- package/build/esm/index.mjs +422 -66
- package/build/esm/index.mjs.map +4 -4
- package/build-examples/cjs/example_mcp_local.js +9 -7
- package/build-examples/cjs/example_mcp_local.js.map +4 -4
- package/build-examples/cjs/example_mcp_remote.js +9 -7
- package/build-examples/cjs/example_mcp_remote.js.map +4 -4
- package/build-examples/esm/example_mcp_local.mjs +9 -7
- package/build-examples/esm/example_mcp_local.mjs.map +4 -4
- package/build-examples/esm/example_mcp_remote.mjs +9 -7
- package/build-examples/esm/example_mcp_remote.mjs.map +4 -4
- package/package.json +2 -2
- package/types/MCPBase.d.ts +0 -49
- package/types/MCPLocal.d.ts +0 -32
- package/types/MCPRemote.d.ts +0 -58
- package/types/PluginOptions.d.ts +0 -6
- package/types/index.d.ts +0 -3
- package/types/schemas/index.d.ts +0 -15
- package/types/schemas/marketData.d.ts +0 -48
- package/types/schemas/schemas.d.ts +0 -168
- package/types/tools/index.d.ts +0 -17
- package/types/tools/marketData.d.ts +0 -40
- package/types/tools/order.d.ts +0 -12
- package/types/tools/parse.d.ts +0 -5
- package/types/tools/parseToJSON.d.ts +0 -5
- package/types/utils/messageHandler.d.ts +0 -12
package/build/cjs/MCPRemote.js
CHANGED
|
@@ -310,17 +310,348 @@ var toolSchemas = {
|
|
|
310
310
|
},
|
|
311
311
|
required: ["symbol"]
|
|
312
312
|
}
|
|
313
|
+
},
|
|
314
|
+
technicalAnalysis: {
|
|
315
|
+
description: "Performs comprehensive technical analysis on market data for a given symbol, including indicators like SMA, EMA, RSI, Bollinger Bands, and trading signals",
|
|
316
|
+
schema: {
|
|
317
|
+
type: "object",
|
|
318
|
+
properties: {
|
|
319
|
+
symbol: {
|
|
320
|
+
type: "string",
|
|
321
|
+
description: "The trading symbol to analyze (e.g., AAPL, MSFT, EURUSD)"
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
required: ["symbol"]
|
|
325
|
+
}
|
|
313
326
|
}
|
|
314
327
|
};
|
|
315
328
|
|
|
329
|
+
// src/tools/analytics.ts
|
|
330
|
+
function sum(numbers) {
|
|
331
|
+
return numbers.reduce((acc, val) => acc + val, 0);
|
|
332
|
+
}
|
|
333
|
+
var TechnicalAnalyzer = class {
|
|
334
|
+
prices;
|
|
335
|
+
volumes;
|
|
336
|
+
highs;
|
|
337
|
+
lows;
|
|
338
|
+
constructor(data) {
|
|
339
|
+
this.prices = data.map((d) => d.trade > 0 ? d.trade : d.midPrice);
|
|
340
|
+
this.volumes = data.map((d) => d.volume);
|
|
341
|
+
this.highs = data.map((d) => d.tradingSessionHighPrice > 0 ? d.tradingSessionHighPrice : d.trade);
|
|
342
|
+
this.lows = data.map((d) => d.tradingSessionLowPrice > 0 ? d.tradingSessionLowPrice : d.trade);
|
|
343
|
+
}
|
|
344
|
+
// Calculate Simple Moving Average
|
|
345
|
+
calculateSMA(data, period) {
|
|
346
|
+
const sma = [];
|
|
347
|
+
for (let i = period - 1; i < data.length; i++) {
|
|
348
|
+
const sum2 = data.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0);
|
|
349
|
+
sma.push(sum2 / period);
|
|
350
|
+
}
|
|
351
|
+
return sma;
|
|
352
|
+
}
|
|
353
|
+
// Calculate Exponential Moving Average
|
|
354
|
+
calculateEMA(data, period) {
|
|
355
|
+
const multiplier = 2 / (period + 1);
|
|
356
|
+
const ema = [data[0]];
|
|
357
|
+
for (let i = 1; i < data.length; i++) {
|
|
358
|
+
ema.push(data[i] * multiplier + ema[i - 1] * (1 - multiplier));
|
|
359
|
+
}
|
|
360
|
+
return ema;
|
|
361
|
+
}
|
|
362
|
+
// Calculate RSI
|
|
363
|
+
calculateRSI(data, period = 14) {
|
|
364
|
+
if (data.length < period + 1) return [];
|
|
365
|
+
const changes = [];
|
|
366
|
+
for (let i = 1; i < data.length; i++) {
|
|
367
|
+
changes.push(data[i] - data[i - 1]);
|
|
368
|
+
}
|
|
369
|
+
const gains = changes.map((change) => change > 0 ? change : 0);
|
|
370
|
+
const losses = changes.map((change) => change < 0 ? Math.abs(change) : 0);
|
|
371
|
+
let avgGain = gains.slice(0, period).reduce((a, b) => a + b, 0) / period;
|
|
372
|
+
let avgLoss = losses.slice(0, period).reduce((a, b) => a + b, 0) / period;
|
|
373
|
+
const rsi = [];
|
|
374
|
+
for (let i = period; i < changes.length; i++) {
|
|
375
|
+
const rs = avgGain / avgLoss;
|
|
376
|
+
rsi.push(100 - 100 / (1 + rs));
|
|
377
|
+
avgGain = (avgGain * (period - 1) + gains[i]) / period;
|
|
378
|
+
avgLoss = (avgLoss * (period - 1) + losses[i]) / period;
|
|
379
|
+
}
|
|
380
|
+
return rsi;
|
|
381
|
+
}
|
|
382
|
+
// Calculate Bollinger Bands
|
|
383
|
+
calculateBollingerBands(data, period = 20, stdDev = 2) {
|
|
384
|
+
if (data.length < period) return [];
|
|
385
|
+
const sma = this.calculateSMA(data, period);
|
|
386
|
+
const bands = [];
|
|
387
|
+
for (let i = 0; i < sma.length; i++) {
|
|
388
|
+
const dataSlice = data.slice(i, i + period);
|
|
389
|
+
const mean = sma[i];
|
|
390
|
+
const variance = dataSlice.reduce((sum2, price) => sum2 + (price - mean) ** 2, 0) / period;
|
|
391
|
+
const standardDeviation = Math.sqrt(variance);
|
|
392
|
+
bands.push({
|
|
393
|
+
upper: mean + standardDeviation * stdDev,
|
|
394
|
+
middle: mean,
|
|
395
|
+
lower: mean - standardDeviation * stdDev
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
return bands;
|
|
399
|
+
}
|
|
400
|
+
// Calculate maximum drawdown
|
|
401
|
+
calculateMaxDrawdown(prices) {
|
|
402
|
+
let maxPrice = prices[0];
|
|
403
|
+
let maxDrawdown = 0;
|
|
404
|
+
for (let i = 1; i < prices.length; i++) {
|
|
405
|
+
if (prices[i] > maxPrice) {
|
|
406
|
+
maxPrice = prices[i];
|
|
407
|
+
}
|
|
408
|
+
const drawdown = (maxPrice - prices[i]) / maxPrice;
|
|
409
|
+
if (drawdown > maxDrawdown) {
|
|
410
|
+
maxDrawdown = drawdown;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return maxDrawdown;
|
|
414
|
+
}
|
|
415
|
+
// Calculate price changes for volatility
|
|
416
|
+
calculatePriceChanges() {
|
|
417
|
+
const changes = [];
|
|
418
|
+
for (let i = 1; i < this.prices.length; i++) {
|
|
419
|
+
changes.push((this.prices[i] - this.prices[i - 1]) / this.prices[i - 1]);
|
|
420
|
+
}
|
|
421
|
+
return changes;
|
|
422
|
+
}
|
|
423
|
+
// Generate comprehensive market analysis
|
|
424
|
+
analyze() {
|
|
425
|
+
const currentPrice = this.prices[this.prices.length - 1];
|
|
426
|
+
const startPrice = this.prices[0];
|
|
427
|
+
const sessionHigh = Math.max(...this.highs);
|
|
428
|
+
const sessionLow = Math.min(...this.lows);
|
|
429
|
+
const totalVolume = sum(this.volumes);
|
|
430
|
+
const avgVolume = totalVolume / this.volumes.length;
|
|
431
|
+
const priceChanges = this.calculatePriceChanges();
|
|
432
|
+
const volatility = priceChanges.length > 0 ? Math.sqrt(
|
|
433
|
+
priceChanges.reduce((sum2, change) => sum2 + change ** 2, 0) / priceChanges.length
|
|
434
|
+
) * Math.sqrt(252) * 100 : 0;
|
|
435
|
+
const sessionReturn = (currentPrice - startPrice) / startPrice * 100;
|
|
436
|
+
const pricePosition = (currentPrice - sessionLow) / (sessionHigh - sessionLow) * 100;
|
|
437
|
+
const trueVWAP = this.prices.reduce((sum2, price, i) => sum2 + price * this.volumes[i], 0) / totalVolume;
|
|
438
|
+
const momentum5 = this.prices.length > 5 ? (currentPrice - this.prices[Math.max(0, this.prices.length - 6)]) / this.prices[Math.max(0, this.prices.length - 6)] * 100 : 0;
|
|
439
|
+
const momentum10 = this.prices.length > 10 ? (currentPrice - this.prices[Math.max(0, this.prices.length - 11)]) / this.prices[Math.max(0, this.prices.length - 11)] * 100 : 0;
|
|
440
|
+
const maxDrawdown = this.calculateMaxDrawdown(this.prices);
|
|
441
|
+
return {
|
|
442
|
+
currentPrice,
|
|
443
|
+
startPrice,
|
|
444
|
+
sessionHigh,
|
|
445
|
+
sessionLow,
|
|
446
|
+
totalVolume,
|
|
447
|
+
avgVolume,
|
|
448
|
+
volatility,
|
|
449
|
+
sessionReturn,
|
|
450
|
+
pricePosition,
|
|
451
|
+
trueVWAP,
|
|
452
|
+
momentum5,
|
|
453
|
+
momentum10,
|
|
454
|
+
maxDrawdown
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
// Generate technical indicators
|
|
458
|
+
getTechnicalIndicators() {
|
|
459
|
+
return {
|
|
460
|
+
sma5: this.calculateSMA(this.prices, 5),
|
|
461
|
+
sma10: this.calculateSMA(this.prices, 10),
|
|
462
|
+
ema8: this.calculateEMA(this.prices, 8),
|
|
463
|
+
ema21: this.calculateEMA(this.prices, 21),
|
|
464
|
+
rsi: this.calculateRSI(this.prices, 14),
|
|
465
|
+
bollinger: this.calculateBollingerBands(this.prices, 20, 2)
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
// Generate trading signals
|
|
469
|
+
generateSignals() {
|
|
470
|
+
const analysis = this.analyze();
|
|
471
|
+
let bullishSignals = 0;
|
|
472
|
+
let bearishSignals = 0;
|
|
473
|
+
const signals = [];
|
|
474
|
+
if (analysis.currentPrice > analysis.trueVWAP) {
|
|
475
|
+
signals.push(
|
|
476
|
+
`\u2713 BULLISH: Price above VWAP (+${((analysis.currentPrice - analysis.trueVWAP) / analysis.trueVWAP * 100).toFixed(2)}%)`
|
|
477
|
+
);
|
|
478
|
+
bullishSignals++;
|
|
479
|
+
} else {
|
|
480
|
+
signals.push(
|
|
481
|
+
`\u2717 BEARISH: Price below VWAP (${((analysis.currentPrice - analysis.trueVWAP) / analysis.trueVWAP * 100).toFixed(2)}%)`
|
|
482
|
+
);
|
|
483
|
+
bearishSignals++;
|
|
484
|
+
}
|
|
485
|
+
if (analysis.momentum5 > 0 && analysis.momentum10 > 0) {
|
|
486
|
+
signals.push("\u2713 BULLISH: Positive momentum on both timeframes");
|
|
487
|
+
bullishSignals++;
|
|
488
|
+
} else if (analysis.momentum5 < 0 && analysis.momentum10 < 0) {
|
|
489
|
+
signals.push("\u2717 BEARISH: Negative momentum on both timeframes");
|
|
490
|
+
bearishSignals++;
|
|
491
|
+
} else {
|
|
492
|
+
signals.push("\u25D0 MIXED: Conflicting momentum signals");
|
|
493
|
+
}
|
|
494
|
+
const currentVolume = this.volumes[this.volumes.length - 1];
|
|
495
|
+
const volumeRatio = currentVolume / analysis.avgVolume;
|
|
496
|
+
if (volumeRatio > 1.2 && analysis.sessionReturn > 0) {
|
|
497
|
+
signals.push("\u2713 BULLISH: Above-average volume supporting upward move");
|
|
498
|
+
bullishSignals++;
|
|
499
|
+
} else if (volumeRatio > 1.2 && analysis.sessionReturn < 0) {
|
|
500
|
+
signals.push("\u2717 BEARISH: Above-average volume supporting downward move");
|
|
501
|
+
bearishSignals++;
|
|
502
|
+
} else {
|
|
503
|
+
signals.push("\u25D0 NEUTRAL: Volume not providing clear direction");
|
|
504
|
+
}
|
|
505
|
+
if (analysis.pricePosition > 65 && analysis.volatility > 30) {
|
|
506
|
+
signals.push("\u2717 BEARISH: High in range with elevated volatility - reversal risk");
|
|
507
|
+
bearishSignals++;
|
|
508
|
+
} else if (analysis.pricePosition < 35 && analysis.volatility > 30) {
|
|
509
|
+
signals.push("\u2713 BULLISH: Low in range with volatility - potential bounce");
|
|
510
|
+
bullishSignals++;
|
|
511
|
+
} else {
|
|
512
|
+
signals.push("\u25D0 NEUTRAL: Price position and volatility not extreme");
|
|
513
|
+
}
|
|
514
|
+
return { bullishSignals, bearishSignals, signals };
|
|
515
|
+
}
|
|
516
|
+
// Generate comprehensive JSON analysis
|
|
517
|
+
generateJSONAnalysis(symbol) {
|
|
518
|
+
const analysis = this.analyze();
|
|
519
|
+
const indicators = this.getTechnicalIndicators();
|
|
520
|
+
const signals = this.generateSignals();
|
|
521
|
+
const currentSMA5 = indicators.sma5.length > 0 ? indicators.sma5[indicators.sma5.length - 1] : null;
|
|
522
|
+
const currentSMA10 = indicators.sma10.length > 0 ? indicators.sma10[indicators.sma10.length - 1] : null;
|
|
523
|
+
const currentEMA8 = indicators.ema8[indicators.ema8.length - 1];
|
|
524
|
+
const currentEMA21 = indicators.ema21[indicators.ema21.length - 1];
|
|
525
|
+
const currentRSI = indicators.rsi.length > 0 ? indicators.rsi[indicators.rsi.length - 1] : null;
|
|
526
|
+
const currentBB = indicators.bollinger.length > 0 ? indicators.bollinger[indicators.bollinger.length - 1] : null;
|
|
527
|
+
const currentVolume = this.volumes[this.volumes.length - 1];
|
|
528
|
+
const volumeRatio = currentVolume / analysis.avgVolume;
|
|
529
|
+
const currentDrawdown = (analysis.sessionHigh - analysis.currentPrice) / analysis.sessionHigh * 100;
|
|
530
|
+
const rangeWidth = (analysis.sessionHigh - analysis.sessionLow) / analysis.sessionLow * 100;
|
|
531
|
+
const priceVsVWAP = (analysis.currentPrice - analysis.trueVWAP) / analysis.trueVWAP * 100;
|
|
532
|
+
const totalScore = signals.bullishSignals - signals.bearishSignals;
|
|
533
|
+
const overallSignal = totalScore > 0 ? "BULLISH_BIAS" : totalScore < 0 ? "BEARISH_BIAS" : "NEUTRAL";
|
|
534
|
+
const targetEntry = Math.max(analysis.sessionLow * 1.005, analysis.trueVWAP * 0.998);
|
|
535
|
+
const stopLoss = analysis.sessionLow * 0.995;
|
|
536
|
+
const profitTarget = analysis.sessionHigh * 0.995;
|
|
537
|
+
const riskRewardRatio = (profitTarget - analysis.currentPrice) / (analysis.currentPrice - stopLoss);
|
|
538
|
+
return {
|
|
539
|
+
symbol,
|
|
540
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
541
|
+
marketStructure: {
|
|
542
|
+
currentPrice: analysis.currentPrice,
|
|
543
|
+
startPrice: analysis.startPrice,
|
|
544
|
+
sessionHigh: analysis.sessionHigh,
|
|
545
|
+
sessionLow: analysis.sessionLow,
|
|
546
|
+
rangeWidth,
|
|
547
|
+
totalVolume: analysis.totalVolume,
|
|
548
|
+
sessionPerformance: analysis.sessionReturn,
|
|
549
|
+
positionInRange: analysis.pricePosition
|
|
550
|
+
},
|
|
551
|
+
volatility: {
|
|
552
|
+
impliedVolatility: analysis.volatility,
|
|
553
|
+
maxDrawdown: analysis.maxDrawdown * 100,
|
|
554
|
+
currentDrawdown
|
|
555
|
+
},
|
|
556
|
+
technicalIndicators: {
|
|
557
|
+
sma5: currentSMA5,
|
|
558
|
+
sma10: currentSMA10,
|
|
559
|
+
ema8: currentEMA8,
|
|
560
|
+
ema21: currentEMA21,
|
|
561
|
+
rsi: currentRSI,
|
|
562
|
+
bollingerBands: currentBB ? {
|
|
563
|
+
upper: currentBB.upper,
|
|
564
|
+
middle: currentBB.middle,
|
|
565
|
+
lower: currentBB.lower,
|
|
566
|
+
position: (analysis.currentPrice - currentBB.lower) / (currentBB.upper - currentBB.lower) * 100
|
|
567
|
+
} : null
|
|
568
|
+
},
|
|
569
|
+
volumeAnalysis: {
|
|
570
|
+
currentVolume,
|
|
571
|
+
averageVolume: Math.round(analysis.avgVolume),
|
|
572
|
+
volumeRatio,
|
|
573
|
+
trueVWAP: analysis.trueVWAP,
|
|
574
|
+
priceVsVWAP
|
|
575
|
+
},
|
|
576
|
+
momentum: {
|
|
577
|
+
momentum5: analysis.momentum5,
|
|
578
|
+
momentum10: analysis.momentum10,
|
|
579
|
+
sessionROC: analysis.sessionReturn
|
|
580
|
+
},
|
|
581
|
+
tradingSignals: {
|
|
582
|
+
...signals,
|
|
583
|
+
overallSignal,
|
|
584
|
+
signalScore: totalScore
|
|
585
|
+
},
|
|
586
|
+
riskManagement: {
|
|
587
|
+
targetEntry,
|
|
588
|
+
stopLoss,
|
|
589
|
+
profitTarget,
|
|
590
|
+
riskRewardRatio
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
var createTechnicalAnalysisHandler = (marketDataPrices) => {
|
|
596
|
+
return async (args) => {
|
|
597
|
+
try {
|
|
598
|
+
const symbol = args.symbol;
|
|
599
|
+
const priceHistory = marketDataPrices.get(symbol) || [];
|
|
600
|
+
if (priceHistory.length === 0) {
|
|
601
|
+
return {
|
|
602
|
+
content: [
|
|
603
|
+
{
|
|
604
|
+
type: "text",
|
|
605
|
+
text: `No price data available for ${symbol}. Please request market data first.`,
|
|
606
|
+
uri: "technicalAnalysis"
|
|
607
|
+
}
|
|
608
|
+
]
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
const analyzer = new TechnicalAnalyzer(priceHistory);
|
|
612
|
+
const analysis = analyzer.generateJSONAnalysis(symbol);
|
|
613
|
+
return {
|
|
614
|
+
content: [
|
|
615
|
+
{
|
|
616
|
+
type: "text",
|
|
617
|
+
text: `Technical Analysis for ${symbol}:
|
|
618
|
+
|
|
619
|
+
${JSON.stringify(analysis, null, 2)}`,
|
|
620
|
+
uri: "technicalAnalysis"
|
|
621
|
+
}
|
|
622
|
+
]
|
|
623
|
+
};
|
|
624
|
+
} catch (error) {
|
|
625
|
+
return {
|
|
626
|
+
content: [
|
|
627
|
+
{
|
|
628
|
+
type: "text",
|
|
629
|
+
text: `Error performing technical analysis: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
630
|
+
uri: "technicalAnalysis"
|
|
631
|
+
}
|
|
632
|
+
],
|
|
633
|
+
isError: true
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
};
|
|
638
|
+
|
|
316
639
|
// src/tools/marketData.ts
|
|
317
640
|
var import_fixparser = require("fixparser");
|
|
318
641
|
var import_quickchart_js = __toESM(require("quickchart-js"), 1);
|
|
319
642
|
var createMarketDataRequestHandler = (parser, pendingRequests) => {
|
|
320
643
|
return async (args) => {
|
|
321
644
|
try {
|
|
645
|
+
parser.logger.log({
|
|
646
|
+
level: "info",
|
|
647
|
+
message: `Sending market data request for symbols: ${args.symbols.join(", ")}`
|
|
648
|
+
});
|
|
322
649
|
const response = new Promise((resolve) => {
|
|
323
650
|
pendingRequests.set(args.mdReqID, resolve);
|
|
651
|
+
parser.logger.log({
|
|
652
|
+
level: "info",
|
|
653
|
+
message: `Registered callback for market data request ID: ${args.mdReqID}`
|
|
654
|
+
});
|
|
324
655
|
});
|
|
325
656
|
const entryTypes = args.mdEntryTypes || [
|
|
326
657
|
import_fixparser.MDEntryType.Bid,
|
|
@@ -389,6 +720,10 @@ var createMarketDataRequestHandler = (parser, pendingRequests) => {
|
|
|
389
720
|
});
|
|
390
721
|
const mdr = parser.createMessage(...messageFields);
|
|
391
722
|
if (!parser.connected) {
|
|
723
|
+
parser.logger.log({
|
|
724
|
+
level: "error",
|
|
725
|
+
message: "Not connected. Cannot send market data request."
|
|
726
|
+
});
|
|
392
727
|
return {
|
|
393
728
|
content: [
|
|
394
729
|
{
|
|
@@ -400,8 +735,16 @@ var createMarketDataRequestHandler = (parser, pendingRequests) => {
|
|
|
400
735
|
isError: true
|
|
401
736
|
};
|
|
402
737
|
}
|
|
738
|
+
parser.logger.log({
|
|
739
|
+
level: "info",
|
|
740
|
+
message: `Sending market data request message: ${JSON.stringify(mdr?.toFIXJSON())}`
|
|
741
|
+
});
|
|
403
742
|
parser.send(mdr);
|
|
404
743
|
const fixData = await response;
|
|
744
|
+
parser.logger.log({
|
|
745
|
+
level: "info",
|
|
746
|
+
message: `Received market data response for request ID: ${args.mdReqID}`
|
|
747
|
+
});
|
|
405
748
|
return {
|
|
406
749
|
content: [
|
|
407
750
|
{
|
|
@@ -450,6 +793,9 @@ var createGetStockGraphHandler = (marketDataPrices) => {
|
|
|
450
793
|
const offerData = priceHistory.map((point) => point.offer);
|
|
451
794
|
const spreadData = priceHistory.map((point) => point.spread);
|
|
452
795
|
const volumeData = priceHistory.map((point) => point.volume);
|
|
796
|
+
const tradeData = priceHistory.map((point) => point.trade);
|
|
797
|
+
const vwapData = priceHistory.map((point) => point.vwap);
|
|
798
|
+
const twapData = priceHistory.map((point) => point.twap);
|
|
453
799
|
const config = {
|
|
454
800
|
type: "line",
|
|
455
801
|
data: {
|
|
@@ -479,6 +825,30 @@ var createGetStockGraphHandler = (marketDataPrices) => {
|
|
|
479
825
|
fill: false,
|
|
480
826
|
tension: 0.4
|
|
481
827
|
},
|
|
828
|
+
{
|
|
829
|
+
label: "Trade",
|
|
830
|
+
data: tradeData,
|
|
831
|
+
borderColor: "#ffc107",
|
|
832
|
+
backgroundColor: "rgba(255, 193, 7, 0.1)",
|
|
833
|
+
fill: false,
|
|
834
|
+
tension: 0.4
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
label: "VWAP",
|
|
838
|
+
data: vwapData,
|
|
839
|
+
borderColor: "#17a2b8",
|
|
840
|
+
backgroundColor: "rgba(23, 162, 184, 0.1)",
|
|
841
|
+
fill: false,
|
|
842
|
+
tension: 0.4
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
label: "TWAP",
|
|
846
|
+
data: twapData,
|
|
847
|
+
borderColor: "#6610f2",
|
|
848
|
+
backgroundColor: "rgba(102, 16, 242, 0.1)",
|
|
849
|
+
fill: false,
|
|
850
|
+
tension: 0.4
|
|
851
|
+
},
|
|
482
852
|
{
|
|
483
853
|
label: "Volume",
|
|
484
854
|
data: volumeData,
|
|
@@ -524,7 +894,7 @@ var createGetStockGraphHandler = (marketDataPrices) => {
|
|
|
524
894
|
content: [
|
|
525
895
|
{
|
|
526
896
|
type: "text",
|
|
527
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to generate
|
|
897
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to generate graph"}`,
|
|
528
898
|
uri: "getStockGraph"
|
|
529
899
|
}
|
|
530
900
|
],
|
|
@@ -562,7 +932,48 @@ var createGetStockPriceHistoryHandler = (marketDataPrices) => {
|
|
|
562
932
|
bid: point.bid,
|
|
563
933
|
offer: point.offer,
|
|
564
934
|
spread: point.spread,
|
|
565
|
-
volume: point.volume
|
|
935
|
+
volume: point.volume,
|
|
936
|
+
trade: point.trade,
|
|
937
|
+
indexValue: point.indexValue,
|
|
938
|
+
openingPrice: point.openingPrice,
|
|
939
|
+
closingPrice: point.closingPrice,
|
|
940
|
+
settlementPrice: point.settlementPrice,
|
|
941
|
+
tradingSessionHighPrice: point.tradingSessionHighPrice,
|
|
942
|
+
tradingSessionLowPrice: point.tradingSessionLowPrice,
|
|
943
|
+
vwap: point.vwap,
|
|
944
|
+
imbalance: point.imbalance,
|
|
945
|
+
openInterest: point.openInterest,
|
|
946
|
+
compositeUnderlyingPrice: point.compositeUnderlyingPrice,
|
|
947
|
+
simulatedSellPrice: point.simulatedSellPrice,
|
|
948
|
+
simulatedBuyPrice: point.simulatedBuyPrice,
|
|
949
|
+
marginRate: point.marginRate,
|
|
950
|
+
midPrice: point.midPrice,
|
|
951
|
+
emptyBook: point.emptyBook,
|
|
952
|
+
settleHighPrice: point.settleHighPrice,
|
|
953
|
+
settleLowPrice: point.settleLowPrice,
|
|
954
|
+
priorSettlePrice: point.priorSettlePrice,
|
|
955
|
+
sessionHighBid: point.sessionHighBid,
|
|
956
|
+
sessionLowOffer: point.sessionLowOffer,
|
|
957
|
+
earlyPrices: point.earlyPrices,
|
|
958
|
+
auctionClearingPrice: point.auctionClearingPrice,
|
|
959
|
+
swapValueFactor: point.swapValueFactor,
|
|
960
|
+
dailyValueAdjustmentForLongPositions: point.dailyValueAdjustmentForLongPositions,
|
|
961
|
+
cumulativeValueAdjustmentForLongPositions: point.cumulativeValueAdjustmentForLongPositions,
|
|
962
|
+
dailyValueAdjustmentForShortPositions: point.dailyValueAdjustmentForShortPositions,
|
|
963
|
+
cumulativeValueAdjustmentForShortPositions: point.cumulativeValueAdjustmentForShortPositions,
|
|
964
|
+
fixingPrice: point.fixingPrice,
|
|
965
|
+
cashRate: point.cashRate,
|
|
966
|
+
recoveryRate: point.recoveryRate,
|
|
967
|
+
recoveryRateForLong: point.recoveryRateForLong,
|
|
968
|
+
recoveryRateForShort: point.recoveryRateForShort,
|
|
969
|
+
marketBid: point.marketBid,
|
|
970
|
+
marketOffer: point.marketOffer,
|
|
971
|
+
shortSaleMinPrice: point.shortSaleMinPrice,
|
|
972
|
+
previousClosingPrice: point.previousClosingPrice,
|
|
973
|
+
thresholdLimitPriceBanding: point.thresholdLimitPriceBanding,
|
|
974
|
+
dailyFinancingValue: point.dailyFinancingValue,
|
|
975
|
+
accruedFinancingValue: point.accruedFinancingValue,
|
|
976
|
+
twap: point.twap
|
|
566
977
|
}))
|
|
567
978
|
},
|
|
568
979
|
null,
|
|
@@ -577,7 +988,7 @@ var createGetStockPriceHistoryHandler = (marketDataPrices) => {
|
|
|
577
988
|
content: [
|
|
578
989
|
{
|
|
579
990
|
type: "text",
|
|
580
|
-
text: `Error: ${error instanceof Error ? error.message : "Failed to get
|
|
991
|
+
text: `Error: ${error instanceof Error ? error.message : "Failed to get price history"}`,
|
|
581
992
|
uri: "getStockPriceHistory"
|
|
582
993
|
}
|
|
583
994
|
],
|
|
@@ -685,7 +1096,7 @@ Parameters verified:
|
|
|
685
1096
|
- Symbol: ${args.symbol}
|
|
686
1097
|
- TimeInForce: ${args.timeInForce} (${timeInForceNames[args.timeInForce]})
|
|
687
1098
|
|
|
688
|
-
To execute this order, call the executeOrder tool with these exact same parameters
|
|
1099
|
+
To execute this order, call the executeOrder tool with these exact same parameters. Important: The user has to explicitly confirm before executeOrder is called!`,
|
|
689
1100
|
uri: "verifyOrder"
|
|
690
1101
|
}
|
|
691
1102
|
]
|
|
@@ -881,16 +1292,16 @@ var createToolHandlers = (parser, verifiedOrders, pendingRequests, marketDataPri
|
|
|
881
1292
|
executeOrder: createExecuteOrderHandler(parser, verifiedOrders, pendingRequests),
|
|
882
1293
|
marketDataRequest: createMarketDataRequestHandler(parser, pendingRequests),
|
|
883
1294
|
getStockGraph: createGetStockGraphHandler(marketDataPrices),
|
|
884
|
-
getStockPriceHistory: createGetStockPriceHistoryHandler(marketDataPrices)
|
|
1295
|
+
getStockPriceHistory: createGetStockPriceHistoryHandler(marketDataPrices),
|
|
1296
|
+
technicalAnalysis: createTechnicalAnalysisHandler(marketDataPrices)
|
|
885
1297
|
});
|
|
886
1298
|
|
|
887
1299
|
// src/utils/messageHandler.ts
|
|
888
1300
|
var import_fixparser3 = require("fixparser");
|
|
1301
|
+
function getEnumValue(enumObj, name) {
|
|
1302
|
+
return enumObj[name] || name;
|
|
1303
|
+
}
|
|
889
1304
|
function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPriceHistory, onPriceUpdate) {
|
|
890
|
-
parser.logger.log({
|
|
891
|
-
level: "info",
|
|
892
|
-
message: `MCP Server received message: ${message.messageType}: ${message.description}`
|
|
893
|
-
});
|
|
894
1305
|
const msgType = message.messageType;
|
|
895
1306
|
if (msgType === import_fixparser3.Messages.MarketDataSnapshotFullRefresh || msgType === import_fixparser3.Messages.MarketDataIncrementalRefresh) {
|
|
896
1307
|
const symbol = message.getField(import_fixparser3.Fields.Symbol)?.value;
|
|
@@ -948,7 +1359,8 @@ function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPr
|
|
|
948
1359
|
const entryType = entry.MDEntryType;
|
|
949
1360
|
const price = entry.MDEntryPx ? Number.parseFloat(entry.MDEntryPx) : 0;
|
|
950
1361
|
const size = entry.MDEntrySize ? Number.parseFloat(entry.MDEntrySize) : 0;
|
|
951
|
-
|
|
1362
|
+
const enumValue = getEnumValue(import_fixparser3.MDEntryType, entryType);
|
|
1363
|
+
switch (enumValue) {
|
|
952
1364
|
case import_fixparser3.MDEntryType.Bid:
|
|
953
1365
|
data.bid = price;
|
|
954
1366
|
break;
|
|
@@ -1215,25 +1627,13 @@ var MCPRemote = class extends MCPBase {
|
|
|
1215
1627
|
}
|
|
1216
1628
|
});
|
|
1217
1629
|
this.httpServer = (0, import_node_http.createServer)(async (req, res) => {
|
|
1218
|
-
this.logger?.log({
|
|
1219
|
-
level: "info",
|
|
1220
|
-
message: `Incoming request: ${req.method} ${req.url}`
|
|
1221
|
-
});
|
|
1222
1630
|
if (!req.url || !req.method) {
|
|
1223
|
-
this.logger?.log({
|
|
1224
|
-
level: "error",
|
|
1225
|
-
message: "Invalid request: missing URL or method"
|
|
1226
|
-
});
|
|
1227
1631
|
res.writeHead(400);
|
|
1228
1632
|
res.end("Bad Request");
|
|
1229
1633
|
return;
|
|
1230
1634
|
}
|
|
1231
1635
|
if (req.url === "/mcp") {
|
|
1232
1636
|
const sessionId = req.headers["mcp-session-id"];
|
|
1233
|
-
this.logger?.log({
|
|
1234
|
-
level: "info",
|
|
1235
|
-
message: `MCP request received. Session ID: ${sessionId || "none"}, headers: ${req.headers}`
|
|
1236
|
-
});
|
|
1237
1637
|
if (req.method === "POST") {
|
|
1238
1638
|
const bodyChunks = [];
|
|
1239
1639
|
req.on("data", (chunk) => {
|
|
@@ -1244,47 +1644,23 @@ var MCPRemote = class extends MCPBase {
|
|
|
1244
1644
|
const body = Buffer.concat(bodyChunks).toString();
|
|
1245
1645
|
try {
|
|
1246
1646
|
parsed = JSON.parse(body);
|
|
1247
|
-
this.logger?.log({
|
|
1248
|
-
level: "info",
|
|
1249
|
-
message: `Parsed request body: ${JSON.stringify(parsed)}`
|
|
1250
|
-
});
|
|
1251
1647
|
} catch (err) {
|
|
1252
|
-
this.logger?.log({
|
|
1253
|
-
level: "error",
|
|
1254
|
-
message: `Failed to parse JSON body: ${err}`
|
|
1255
|
-
});
|
|
1256
1648
|
res.writeHead(400);
|
|
1257
1649
|
res.end(JSON.stringify({ error: "Invalid JSON" }));
|
|
1258
1650
|
return;
|
|
1259
1651
|
}
|
|
1260
1652
|
let transport;
|
|
1261
1653
|
if (sessionId && transports[sessionId]) {
|
|
1262
|
-
this.logger?.log({
|
|
1263
|
-
level: "info",
|
|
1264
|
-
message: `Using existing transport for session: ${sessionId}`
|
|
1265
|
-
});
|
|
1266
1654
|
transport = transports[sessionId];
|
|
1267
1655
|
} else if (!sessionId && req.method === "POST" && (0, import_types.isInitializeRequest)(parsed)) {
|
|
1268
|
-
this.logger?.log({
|
|
1269
|
-
level: "info",
|
|
1270
|
-
message: "Creating new transport for initialization request"
|
|
1271
|
-
});
|
|
1272
1656
|
transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
1273
1657
|
sessionIdGenerator: () => (0, import_node_crypto.randomUUID)(),
|
|
1274
1658
|
onsessioninitialized: (sessionId2) => {
|
|
1275
|
-
this.logger?.log({
|
|
1276
|
-
level: "info",
|
|
1277
|
-
message: `New session initialized: ${sessionId2}`
|
|
1278
|
-
});
|
|
1279
1659
|
transports[sessionId2] = transport;
|
|
1280
1660
|
}
|
|
1281
1661
|
});
|
|
1282
1662
|
transport.onclose = () => {
|
|
1283
1663
|
if (transport.sessionId) {
|
|
1284
|
-
this.logger?.log({
|
|
1285
|
-
level: "info",
|
|
1286
|
-
message: `Session closed: ${transport.sessionId}`
|
|
1287
|
-
});
|
|
1288
1664
|
delete transports[transport.sessionId];
|
|
1289
1665
|
}
|
|
1290
1666
|
};
|
|
@@ -1295,10 +1671,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1295
1671
|
this.setupTools();
|
|
1296
1672
|
await this.mcpServer.connect(transport);
|
|
1297
1673
|
} else {
|
|
1298
|
-
this.logger?.log({
|
|
1299
|
-
level: "error",
|
|
1300
|
-
message: "Invalid request: No valid session ID provided"
|
|
1301
|
-
});
|
|
1302
1674
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1303
1675
|
res.end(
|
|
1304
1676
|
JSON.stringify({
|
|
@@ -1314,10 +1686,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1314
1686
|
}
|
|
1315
1687
|
try {
|
|
1316
1688
|
await transport.handleRequest(req, res, parsed);
|
|
1317
|
-
this.logger?.log({
|
|
1318
|
-
level: "info",
|
|
1319
|
-
message: "Request handled successfully"
|
|
1320
|
-
});
|
|
1321
1689
|
} catch (error) {
|
|
1322
1690
|
this.logger?.log({
|
|
1323
1691
|
level: "error",
|
|
@@ -1328,10 +1696,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1328
1696
|
});
|
|
1329
1697
|
} else if (req.method === "GET" || req.method === "DELETE") {
|
|
1330
1698
|
if (!sessionId || !transports[sessionId]) {
|
|
1331
|
-
this.logger?.log({
|
|
1332
|
-
level: "error",
|
|
1333
|
-
message: `Invalid session ID for ${req.method} request: ${sessionId}`
|
|
1334
|
-
});
|
|
1335
1699
|
res.writeHead(400);
|
|
1336
1700
|
res.end("Invalid or missing session ID");
|
|
1337
1701
|
return;
|
|
@@ -1339,10 +1703,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1339
1703
|
const transport = transports[sessionId];
|
|
1340
1704
|
try {
|
|
1341
1705
|
await transport.handleRequest(req, res);
|
|
1342
|
-
this.logger?.log({
|
|
1343
|
-
level: "info",
|
|
1344
|
-
message: `${req.method} request handled successfully for session: ${sessionId}`
|
|
1345
|
-
});
|
|
1346
1706
|
} catch (error) {
|
|
1347
1707
|
this.logger?.log({
|
|
1348
1708
|
level: "error",
|
|
@@ -1359,10 +1719,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1359
1719
|
res.end("Method Not Allowed");
|
|
1360
1720
|
}
|
|
1361
1721
|
} else {
|
|
1362
|
-
this.logger?.log({
|
|
1363
|
-
level: "error",
|
|
1364
|
-
message: `Not found: ${req.url}`
|
|
1365
|
-
});
|
|
1366
1722
|
res.writeHead(404);
|
|
1367
1723
|
res.end("Not Found");
|
|
1368
1724
|
}
|