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/index.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;
|
|
@@ -1340,25 +1752,13 @@ var MCPRemote = class extends MCPBase {
|
|
|
1340
1752
|
}
|
|
1341
1753
|
});
|
|
1342
1754
|
this.httpServer = (0, import_node_http.createServer)(async (req, res) => {
|
|
1343
|
-
this.logger?.log({
|
|
1344
|
-
level: "info",
|
|
1345
|
-
message: `Incoming request: ${req.method} ${req.url}`
|
|
1346
|
-
});
|
|
1347
1755
|
if (!req.url || !req.method) {
|
|
1348
|
-
this.logger?.log({
|
|
1349
|
-
level: "error",
|
|
1350
|
-
message: "Invalid request: missing URL or method"
|
|
1351
|
-
});
|
|
1352
1756
|
res.writeHead(400);
|
|
1353
1757
|
res.end("Bad Request");
|
|
1354
1758
|
return;
|
|
1355
1759
|
}
|
|
1356
1760
|
if (req.url === "/mcp") {
|
|
1357
1761
|
const sessionId = req.headers["mcp-session-id"];
|
|
1358
|
-
this.logger?.log({
|
|
1359
|
-
level: "info",
|
|
1360
|
-
message: `MCP request received. Session ID: ${sessionId || "none"}, headers: ${req.headers}`
|
|
1361
|
-
});
|
|
1362
1762
|
if (req.method === "POST") {
|
|
1363
1763
|
const bodyChunks = [];
|
|
1364
1764
|
req.on("data", (chunk) => {
|
|
@@ -1369,47 +1769,23 @@ var MCPRemote = class extends MCPBase {
|
|
|
1369
1769
|
const body = Buffer.concat(bodyChunks).toString();
|
|
1370
1770
|
try {
|
|
1371
1771
|
parsed = JSON.parse(body);
|
|
1372
|
-
this.logger?.log({
|
|
1373
|
-
level: "info",
|
|
1374
|
-
message: `Parsed request body: ${JSON.stringify(parsed)}`
|
|
1375
|
-
});
|
|
1376
1772
|
} catch (err) {
|
|
1377
|
-
this.logger?.log({
|
|
1378
|
-
level: "error",
|
|
1379
|
-
message: `Failed to parse JSON body: ${err}`
|
|
1380
|
-
});
|
|
1381
1773
|
res.writeHead(400);
|
|
1382
1774
|
res.end(JSON.stringify({ error: "Invalid JSON" }));
|
|
1383
1775
|
return;
|
|
1384
1776
|
}
|
|
1385
1777
|
let transport;
|
|
1386
1778
|
if (sessionId && transports[sessionId]) {
|
|
1387
|
-
this.logger?.log({
|
|
1388
|
-
level: "info",
|
|
1389
|
-
message: `Using existing transport for session: ${sessionId}`
|
|
1390
|
-
});
|
|
1391
1779
|
transport = transports[sessionId];
|
|
1392
1780
|
} else if (!sessionId && req.method === "POST" && (0, import_types.isInitializeRequest)(parsed)) {
|
|
1393
|
-
this.logger?.log({
|
|
1394
|
-
level: "info",
|
|
1395
|
-
message: "Creating new transport for initialization request"
|
|
1396
|
-
});
|
|
1397
1781
|
transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
1398
1782
|
sessionIdGenerator: () => (0, import_node_crypto.randomUUID)(),
|
|
1399
1783
|
onsessioninitialized: (sessionId2) => {
|
|
1400
|
-
this.logger?.log({
|
|
1401
|
-
level: "info",
|
|
1402
|
-
message: `New session initialized: ${sessionId2}`
|
|
1403
|
-
});
|
|
1404
1784
|
transports[sessionId2] = transport;
|
|
1405
1785
|
}
|
|
1406
1786
|
});
|
|
1407
1787
|
transport.onclose = () => {
|
|
1408
1788
|
if (transport.sessionId) {
|
|
1409
|
-
this.logger?.log({
|
|
1410
|
-
level: "info",
|
|
1411
|
-
message: `Session closed: ${transport.sessionId}`
|
|
1412
|
-
});
|
|
1413
1789
|
delete transports[transport.sessionId];
|
|
1414
1790
|
}
|
|
1415
1791
|
};
|
|
@@ -1420,10 +1796,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1420
1796
|
this.setupTools();
|
|
1421
1797
|
await this.mcpServer.connect(transport);
|
|
1422
1798
|
} else {
|
|
1423
|
-
this.logger?.log({
|
|
1424
|
-
level: "error",
|
|
1425
|
-
message: "Invalid request: No valid session ID provided"
|
|
1426
|
-
});
|
|
1427
1799
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1428
1800
|
res.end(
|
|
1429
1801
|
JSON.stringify({
|
|
@@ -1439,10 +1811,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1439
1811
|
}
|
|
1440
1812
|
try {
|
|
1441
1813
|
await transport.handleRequest(req, res, parsed);
|
|
1442
|
-
this.logger?.log({
|
|
1443
|
-
level: "info",
|
|
1444
|
-
message: "Request handled successfully"
|
|
1445
|
-
});
|
|
1446
1814
|
} catch (error) {
|
|
1447
1815
|
this.logger?.log({
|
|
1448
1816
|
level: "error",
|
|
@@ -1453,10 +1821,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1453
1821
|
});
|
|
1454
1822
|
} else if (req.method === "GET" || req.method === "DELETE") {
|
|
1455
1823
|
if (!sessionId || !transports[sessionId]) {
|
|
1456
|
-
this.logger?.log({
|
|
1457
|
-
level: "error",
|
|
1458
|
-
message: `Invalid session ID for ${req.method} request: ${sessionId}`
|
|
1459
|
-
});
|
|
1460
1824
|
res.writeHead(400);
|
|
1461
1825
|
res.end("Invalid or missing session ID");
|
|
1462
1826
|
return;
|
|
@@ -1464,10 +1828,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1464
1828
|
const transport = transports[sessionId];
|
|
1465
1829
|
try {
|
|
1466
1830
|
await transport.handleRequest(req, res);
|
|
1467
|
-
this.logger?.log({
|
|
1468
|
-
level: "info",
|
|
1469
|
-
message: `${req.method} request handled successfully for session: ${sessionId}`
|
|
1470
|
-
});
|
|
1471
1831
|
} catch (error) {
|
|
1472
1832
|
this.logger?.log({
|
|
1473
1833
|
level: "error",
|
|
@@ -1484,10 +1844,6 @@ var MCPRemote = class extends MCPBase {
|
|
|
1484
1844
|
res.end("Method Not Allowed");
|
|
1485
1845
|
}
|
|
1486
1846
|
} else {
|
|
1487
|
-
this.logger?.log({
|
|
1488
|
-
level: "error",
|
|
1489
|
-
message: `Not found: ${req.url}`
|
|
1490
|
-
});
|
|
1491
1847
|
res.writeHead(404);
|
|
1492
1848
|
res.end("Not Found");
|
|
1493
1849
|
}
|