fixparser-plugin-mcp 9.1.7-38cee007 → 9.1.7-3c6fd297

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.
@@ -166,7 +166,7 @@ var toolSchemas = {
166
166
  }
167
167
  },
168
168
  executeOrder: {
169
- description: "Executes a verified order. verifyOrder must be called before executeOrder.",
169
+ description: "Executes a verified order. verifyOrder must be called before executeOrder. user has to explicitly allow executeOrder.",
170
170
  schema: {
171
171
  type: "object",
172
172
  properties: {
@@ -310,330 +310,7 @@ 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
- }
326
- }
327
- };
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
313
  }
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
314
  };
638
315
 
639
316
  // src/tools/marketData.ts
@@ -642,63 +319,10 @@ var import_quickchart_js = __toESM(require("quickchart-js"), 1);
642
319
  var createMarketDataRequestHandler = (parser, pendingRequests) => {
643
320
  return async (args) => {
644
321
  try {
645
- parser.logger.log({
646
- level: "info",
647
- message: `Sending market data request for symbols: ${args.symbols.join(", ")}`
648
- });
649
322
  const response = new Promise((resolve) => {
650
323
  pendingRequests.set(args.mdReqID, resolve);
651
- parser.logger.log({
652
- level: "info",
653
- message: `Registered callback for market data request ID: ${args.mdReqID}`
654
- });
655
324
  });
656
- const entryTypes = args.mdEntryTypes || [
657
- import_fixparser.MDEntryType.Bid,
658
- import_fixparser.MDEntryType.Offer,
659
- import_fixparser.MDEntryType.Trade,
660
- import_fixparser.MDEntryType.IndexValue,
661
- import_fixparser.MDEntryType.OpeningPrice,
662
- import_fixparser.MDEntryType.ClosingPrice,
663
- import_fixparser.MDEntryType.SettlementPrice,
664
- import_fixparser.MDEntryType.TradingSessionHighPrice,
665
- import_fixparser.MDEntryType.TradingSessionLowPrice,
666
- import_fixparser.MDEntryType.VWAP,
667
- import_fixparser.MDEntryType.Imbalance,
668
- import_fixparser.MDEntryType.TradeVolume,
669
- import_fixparser.MDEntryType.OpenInterest,
670
- import_fixparser.MDEntryType.CompositeUnderlyingPrice,
671
- import_fixparser.MDEntryType.SimulatedSellPrice,
672
- import_fixparser.MDEntryType.SimulatedBuyPrice,
673
- import_fixparser.MDEntryType.MarginRate,
674
- import_fixparser.MDEntryType.MidPrice,
675
- import_fixparser.MDEntryType.EmptyBook,
676
- import_fixparser.MDEntryType.SettleHighPrice,
677
- import_fixparser.MDEntryType.SettleLowPrice,
678
- import_fixparser.MDEntryType.PriorSettlePrice,
679
- import_fixparser.MDEntryType.SessionHighBid,
680
- import_fixparser.MDEntryType.SessionLowOffer,
681
- import_fixparser.MDEntryType.EarlyPrices,
682
- import_fixparser.MDEntryType.AuctionClearingPrice,
683
- import_fixparser.MDEntryType.SwapValueFactor,
684
- import_fixparser.MDEntryType.DailyValueAdjustmentForLongPositions,
685
- import_fixparser.MDEntryType.CumulativeValueAdjustmentForLongPositions,
686
- import_fixparser.MDEntryType.DailyValueAdjustmentForShortPositions,
687
- import_fixparser.MDEntryType.CumulativeValueAdjustmentForShortPositions,
688
- import_fixparser.MDEntryType.FixingPrice,
689
- import_fixparser.MDEntryType.CashRate,
690
- import_fixparser.MDEntryType.RecoveryRate,
691
- import_fixparser.MDEntryType.RecoveryRateForLong,
692
- import_fixparser.MDEntryType.RecoveryRateForShort,
693
- import_fixparser.MDEntryType.MarketBid,
694
- import_fixparser.MDEntryType.MarketOffer,
695
- import_fixparser.MDEntryType.ShortSaleMinPrice,
696
- import_fixparser.MDEntryType.PreviousClosingPrice,
697
- import_fixparser.MDEntryType.ThresholdLimitPriceBanding,
698
- import_fixparser.MDEntryType.DailyFinancingValue,
699
- import_fixparser.MDEntryType.AccruedFinancingValue,
700
- import_fixparser.MDEntryType.TWAP
701
- ];
325
+ const entryTypes = args.mdEntryTypes || [import_fixparser.MDEntryType.Bid, import_fixparser.MDEntryType.Offer, import_fixparser.MDEntryType.TradeVolume];
702
326
  const messageFields = [
703
327
  new import_fixparser.Field(import_fixparser.Fields.MsgType, import_fixparser.Messages.MarketDataRequest),
704
328
  new import_fixparser.Field(import_fixparser.Fields.SenderCompID, parser.sender),
@@ -720,10 +344,6 @@ var createMarketDataRequestHandler = (parser, pendingRequests) => {
720
344
  });
721
345
  const mdr = parser.createMessage(...messageFields);
722
346
  if (!parser.connected) {
723
- parser.logger.log({
724
- level: "error",
725
- message: "Not connected. Cannot send market data request."
726
- });
727
347
  return {
728
348
  content: [
729
349
  {
@@ -735,16 +355,8 @@ var createMarketDataRequestHandler = (parser, pendingRequests) => {
735
355
  isError: true
736
356
  };
737
357
  }
738
- parser.logger.log({
739
- level: "info",
740
- message: `Sending market data request message: ${JSON.stringify(mdr?.toFIXJSON())}`
741
- });
742
358
  parser.send(mdr);
743
359
  const fixData = await response;
744
- parser.logger.log({
745
- level: "info",
746
- message: `Received market data response for request ID: ${args.mdReqID}`
747
- });
748
360
  return {
749
361
  content: [
750
362
  {
@@ -793,9 +405,6 @@ var createGetStockGraphHandler = (marketDataPrices) => {
793
405
  const offerData = priceHistory.map((point) => point.offer);
794
406
  const spreadData = priceHistory.map((point) => point.spread);
795
407
  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);
799
408
  const config = {
800
409
  type: "line",
801
410
  data: {
@@ -825,30 +434,6 @@ var createGetStockGraphHandler = (marketDataPrices) => {
825
434
  fill: false,
826
435
  tension: 0.4
827
436
  },
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
- },
852
437
  {
853
438
  label: "Volume",
854
439
  data: volumeData,
@@ -894,7 +479,7 @@ var createGetStockGraphHandler = (marketDataPrices) => {
894
479
  content: [
895
480
  {
896
481
  type: "text",
897
- text: `Error: ${error instanceof Error ? error.message : "Failed to generate graph"}`,
482
+ text: `Error: ${error instanceof Error ? error.message : "Failed to generate chart"}`,
898
483
  uri: "getStockGraph"
899
484
  }
900
485
  ],
@@ -932,48 +517,7 @@ var createGetStockPriceHistoryHandler = (marketDataPrices) => {
932
517
  bid: point.bid,
933
518
  offer: point.offer,
934
519
  spread: point.spread,
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
520
+ volume: point.volume
977
521
  }))
978
522
  },
979
523
  null,
@@ -988,7 +532,7 @@ var createGetStockPriceHistoryHandler = (marketDataPrices) => {
988
532
  content: [
989
533
  {
990
534
  type: "text",
991
- text: `Error: ${error instanceof Error ? error.message : "Failed to get price history"}`,
535
+ text: `Error: ${error instanceof Error ? error.message : "Failed to get stock price history"}`,
992
536
  uri: "getStockPriceHistory"
993
537
  }
994
538
  ],
@@ -1096,7 +640,7 @@ Parameters verified:
1096
640
  - Symbol: ${args.symbol}
1097
641
  - TimeInForce: ${args.timeInForce} (${timeInForceNames[args.timeInForce]})
1098
642
 
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!`,
643
+ To execute this order, call the executeOrder tool with these exact same parameters.`,
1100
644
  uri: "verifyOrder"
1101
645
  }
1102
646
  ]
@@ -1292,210 +836,48 @@ var createToolHandlers = (parser, verifiedOrders, pendingRequests, marketDataPri
1292
836
  executeOrder: createExecuteOrderHandler(parser, verifiedOrders, pendingRequests),
1293
837
  marketDataRequest: createMarketDataRequestHandler(parser, pendingRequests),
1294
838
  getStockGraph: createGetStockGraphHandler(marketDataPrices),
1295
- getStockPriceHistory: createGetStockPriceHistoryHandler(marketDataPrices),
1296
- technicalAnalysis: createTechnicalAnalysisHandler(marketDataPrices)
839
+ getStockPriceHistory: createGetStockPriceHistoryHandler(marketDataPrices)
1297
840
  });
1298
841
 
1299
842
  // src/utils/messageHandler.ts
1300
843
  var import_fixparser3 = require("fixparser");
1301
- function getEnumValue(enumObj, name) {
1302
- return enumObj[name] || name;
1303
- }
1304
844
  function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPriceHistory, onPriceUpdate) {
845
+ parser.logger.log({
846
+ level: "info",
847
+ message: `MCP Server received message: ${message.messageType}: ${message.description}`
848
+ });
1305
849
  const msgType = message.messageType;
1306
- if (msgType === import_fixparser3.Messages.MarketDataSnapshotFullRefresh || msgType === import_fixparser3.Messages.MarketDataIncrementalRefresh) {
850
+ if (msgType === import_fixparser3.Messages.MarketDataSnapshotFullRefresh) {
1307
851
  const symbol = message.getField(import_fixparser3.Fields.Symbol)?.value;
1308
- const fixJson = message.toFIXJSON();
1309
- const entries = fixJson.Body?.NoMDEntries || [];
1310
- const data = {
1311
- timestamp: Date.now(),
1312
- bid: 0,
1313
- offer: 0,
1314
- spread: 0,
1315
- volume: 0,
1316
- trade: 0,
1317
- indexValue: 0,
1318
- openingPrice: 0,
1319
- closingPrice: 0,
1320
- settlementPrice: 0,
1321
- tradingSessionHighPrice: 0,
1322
- tradingSessionLowPrice: 0,
1323
- vwap: 0,
1324
- imbalance: 0,
1325
- openInterest: 0,
1326
- compositeUnderlyingPrice: 0,
1327
- simulatedSellPrice: 0,
1328
- simulatedBuyPrice: 0,
1329
- marginRate: 0,
1330
- midPrice: 0,
1331
- emptyBook: 0,
1332
- settleHighPrice: 0,
1333
- settleLowPrice: 0,
1334
- priorSettlePrice: 0,
1335
- sessionHighBid: 0,
1336
- sessionLowOffer: 0,
1337
- earlyPrices: 0,
1338
- auctionClearingPrice: 0,
1339
- swapValueFactor: 0,
1340
- dailyValueAdjustmentForLongPositions: 0,
1341
- cumulativeValueAdjustmentForLongPositions: 0,
1342
- dailyValueAdjustmentForShortPositions: 0,
1343
- cumulativeValueAdjustmentForShortPositions: 0,
1344
- fixingPrice: 0,
1345
- cashRate: 0,
1346
- recoveryRate: 0,
1347
- recoveryRateForLong: 0,
1348
- recoveryRateForShort: 0,
1349
- marketBid: 0,
1350
- marketOffer: 0,
1351
- shortSaleMinPrice: 0,
1352
- previousClosingPrice: 0,
1353
- thresholdLimitPriceBanding: 0,
1354
- dailyFinancingValue: 0,
1355
- accruedFinancingValue: 0,
1356
- twap: 0
1357
- };
1358
- for (const entry of entries) {
1359
- const entryType = entry.MDEntryType;
1360
- const price = entry.MDEntryPx ? Number.parseFloat(entry.MDEntryPx) : 0;
1361
- const size = entry.MDEntrySize ? Number.parseFloat(entry.MDEntrySize) : 0;
1362
- const enumValue = getEnumValue(import_fixparser3.MDEntryType, entryType);
1363
- switch (enumValue) {
1364
- case import_fixparser3.MDEntryType.Bid:
1365
- data.bid = price;
1366
- break;
1367
- case import_fixparser3.MDEntryType.Offer:
1368
- data.offer = price;
1369
- break;
1370
- case import_fixparser3.MDEntryType.Trade:
1371
- data.trade = price;
1372
- break;
1373
- case import_fixparser3.MDEntryType.IndexValue:
1374
- data.indexValue = price;
1375
- break;
1376
- case import_fixparser3.MDEntryType.OpeningPrice:
1377
- data.openingPrice = price;
1378
- break;
1379
- case import_fixparser3.MDEntryType.ClosingPrice:
1380
- data.closingPrice = price;
1381
- break;
1382
- case import_fixparser3.MDEntryType.SettlementPrice:
1383
- data.settlementPrice = price;
1384
- break;
1385
- case import_fixparser3.MDEntryType.TradingSessionHighPrice:
1386
- data.tradingSessionHighPrice = price;
1387
- break;
1388
- case import_fixparser3.MDEntryType.TradingSessionLowPrice:
1389
- data.tradingSessionLowPrice = price;
1390
- break;
1391
- case import_fixparser3.MDEntryType.VWAP:
1392
- data.vwap = price;
1393
- break;
1394
- case import_fixparser3.MDEntryType.Imbalance:
1395
- data.imbalance = size;
1396
- break;
1397
- case import_fixparser3.MDEntryType.TradeVolume:
1398
- data.volume = size;
1399
- break;
1400
- case import_fixparser3.MDEntryType.OpenInterest:
1401
- data.openInterest = size;
1402
- break;
1403
- case import_fixparser3.MDEntryType.CompositeUnderlyingPrice:
1404
- data.compositeUnderlyingPrice = price;
1405
- break;
1406
- case import_fixparser3.MDEntryType.SimulatedSellPrice:
1407
- data.simulatedSellPrice = price;
1408
- break;
1409
- case import_fixparser3.MDEntryType.SimulatedBuyPrice:
1410
- data.simulatedBuyPrice = price;
1411
- break;
1412
- case import_fixparser3.MDEntryType.MarginRate:
1413
- data.marginRate = price;
1414
- break;
1415
- case import_fixparser3.MDEntryType.MidPrice:
1416
- data.midPrice = price;
1417
- break;
1418
- case import_fixparser3.MDEntryType.EmptyBook:
1419
- data.emptyBook = 1;
1420
- break;
1421
- case import_fixparser3.MDEntryType.SettleHighPrice:
1422
- data.settleHighPrice = price;
1423
- break;
1424
- case import_fixparser3.MDEntryType.SettleLowPrice:
1425
- data.settleLowPrice = price;
1426
- break;
1427
- case import_fixparser3.MDEntryType.PriorSettlePrice:
1428
- data.priorSettlePrice = price;
1429
- break;
1430
- case import_fixparser3.MDEntryType.SessionHighBid:
1431
- data.sessionHighBid = price;
1432
- break;
1433
- case import_fixparser3.MDEntryType.SessionLowOffer:
1434
- data.sessionLowOffer = price;
1435
- break;
1436
- case import_fixparser3.MDEntryType.EarlyPrices:
1437
- data.earlyPrices = price;
1438
- break;
1439
- case import_fixparser3.MDEntryType.AuctionClearingPrice:
1440
- data.auctionClearingPrice = price;
1441
- break;
1442
- case import_fixparser3.MDEntryType.SwapValueFactor:
1443
- data.swapValueFactor = price;
1444
- break;
1445
- case import_fixparser3.MDEntryType.DailyValueAdjustmentForLongPositions:
1446
- data.dailyValueAdjustmentForLongPositions = price;
1447
- break;
1448
- case import_fixparser3.MDEntryType.CumulativeValueAdjustmentForLongPositions:
1449
- data.cumulativeValueAdjustmentForLongPositions = price;
1450
- break;
1451
- case import_fixparser3.MDEntryType.DailyValueAdjustmentForShortPositions:
1452
- data.dailyValueAdjustmentForShortPositions = price;
1453
- break;
1454
- case import_fixparser3.MDEntryType.CumulativeValueAdjustmentForShortPositions:
1455
- data.cumulativeValueAdjustmentForShortPositions = price;
1456
- break;
1457
- case import_fixparser3.MDEntryType.FixingPrice:
1458
- data.fixingPrice = price;
1459
- break;
1460
- case import_fixparser3.MDEntryType.CashRate:
1461
- data.cashRate = price;
1462
- break;
1463
- case import_fixparser3.MDEntryType.RecoveryRate:
1464
- data.recoveryRate = price;
1465
- break;
1466
- case import_fixparser3.MDEntryType.RecoveryRateForLong:
1467
- data.recoveryRateForLong = price;
1468
- break;
1469
- case import_fixparser3.MDEntryType.RecoveryRateForShort:
1470
- data.recoveryRateForShort = price;
1471
- break;
1472
- case import_fixparser3.MDEntryType.MarketBid:
1473
- data.marketBid = price;
1474
- break;
1475
- case import_fixparser3.MDEntryType.MarketOffer:
1476
- data.marketOffer = price;
1477
- break;
1478
- case import_fixparser3.MDEntryType.ShortSaleMinPrice:
1479
- data.shortSaleMinPrice = price;
1480
- break;
1481
- case import_fixparser3.MDEntryType.PreviousClosingPrice:
1482
- data.previousClosingPrice = price;
1483
- break;
1484
- case import_fixparser3.MDEntryType.ThresholdLimitPriceBanding:
1485
- data.thresholdLimitPriceBanding = price;
1486
- break;
1487
- case import_fixparser3.MDEntryType.DailyFinancingValue:
1488
- data.dailyFinancingValue = price;
1489
- break;
1490
- case import_fixparser3.MDEntryType.AccruedFinancingValue:
1491
- data.accruedFinancingValue = price;
1492
- break;
1493
- case import_fixparser3.MDEntryType.TWAP:
1494
- data.twap = price;
1495
- break;
852
+ const entries = message.getField(import_fixparser3.Fields.NoMDEntries)?.value;
853
+ let bid = 0;
854
+ let offer = 0;
855
+ let volume = 0;
856
+ const entryTypes = message.getFields(import_fixparser3.Fields.MDEntryType);
857
+ const entryPrices = message.getFields(import_fixparser3.Fields.MDEntryPx);
858
+ const entrySizes = message.getFields(import_fixparser3.Fields.MDEntrySize);
859
+ if (entryTypes && entryPrices && entrySizes) {
860
+ for (let i = 0; i < entries; i++) {
861
+ const entryType = entryTypes[i]?.value;
862
+ const entryPrice = Number.parseFloat(entryPrices[i]?.value);
863
+ const entrySize = Number.parseFloat(entrySizes[i]?.value);
864
+ if (entryType === import_fixparser3.MDEntryType.Bid) {
865
+ bid = entryPrice;
866
+ } else if (entryType === import_fixparser3.MDEntryType.Offer) {
867
+ offer = entryPrice;
868
+ }
869
+ volume += entrySize;
1496
870
  }
1497
871
  }
1498
- data.spread = data.offer - data.bid;
872
+ const spread = offer - bid;
873
+ const timestamp = Date.now();
874
+ const data = {
875
+ timestamp,
876
+ bid,
877
+ offer,
878
+ spread,
879
+ volume
880
+ };
1499
881
  if (!marketDataPrices.has(symbol)) {
1500
882
  marketDataPrices.set(symbol, []);
1501
883
  }
@@ -1505,14 +887,6 @@ function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPr
1505
887
  prices.splice(0, prices.length - maxPriceHistory);
1506
888
  }
1507
889
  onPriceUpdate?.(symbol, data);
1508
- const mdReqID = message.getField(import_fixparser3.Fields.MDReqID)?.value;
1509
- if (mdReqID) {
1510
- const callback = pendingRequests.get(mdReqID);
1511
- if (callback) {
1512
- callback(message);
1513
- pendingRequests.delete(mdReqID);
1514
- }
1515
- }
1516
890
  } else if (msgType === import_fixparser3.Messages.ExecutionReport) {
1517
891
  const reqId = message.getField(import_fixparser3.Fields.ClOrdID)?.value;
1518
892
  const callback = pendingRequests.get(reqId);
@@ -1525,39 +899,6 @@ function handleMessage(message, parser, pendingRequests, marketDataPrices, maxPr
1525
899
 
1526
900
  // src/MCPRemote.ts
1527
901
  var transports = {};
1528
- function jsonSchemaToZod(schema) {
1529
- if (schema.type === "object") {
1530
- const shape = {};
1531
- for (const [key, prop] of Object.entries(schema.properties || {})) {
1532
- const propSchema = prop;
1533
- if (propSchema.type === "string") {
1534
- if (propSchema.enum) {
1535
- shape[key] = import_zod.z.enum(propSchema.enum);
1536
- } else {
1537
- shape[key] = import_zod.z.string();
1538
- }
1539
- } else if (propSchema.type === "number") {
1540
- shape[key] = import_zod.z.number();
1541
- } else if (propSchema.type === "boolean") {
1542
- shape[key] = import_zod.z.boolean();
1543
- } else if (propSchema.type === "array") {
1544
- if (propSchema.items.type === "string") {
1545
- shape[key] = import_zod.z.array(import_zod.z.string());
1546
- } else if (propSchema.items.type === "number") {
1547
- shape[key] = import_zod.z.array(import_zod.z.number());
1548
- } else if (propSchema.items.type === "boolean") {
1549
- shape[key] = import_zod.z.array(import_zod.z.boolean());
1550
- } else {
1551
- shape[key] = import_zod.z.array(import_zod.z.any());
1552
- }
1553
- } else {
1554
- shape[key] = import_zod.z.any();
1555
- }
1556
- }
1557
- return shape;
1558
- }
1559
- return {};
1560
- }
1561
902
  var MCPRemote = class extends MCPBase {
1562
903
  /**
1563
904
  * Port number the server will listen on.
@@ -1600,7 +941,7 @@ var MCPRemote = class extends MCPBase {
1600
941
  */
1601
942
  marketDataPrices = /* @__PURE__ */ new Map();
1602
943
  /**
1603
- * Maximum number of price history entries to keep per symbol
944
+ * Maximum number of price points to store per symbol
1604
945
  * @private
1605
946
  */
1606
947
  MAX_PRICE_HISTORY = 1e5;
@@ -1622,7 +963,31 @@ var MCPRemote = class extends MCPBase {
1622
963
  this.parser,
1623
964
  this.pendingRequests,
1624
965
  this.marketDataPrices,
1625
- this.MAX_PRICE_HISTORY
966
+ this.MAX_PRICE_HISTORY,
967
+ (symbol, data) => {
968
+ this.mcpServer?.tool(
969
+ "priceUpdate",
970
+ {
971
+ description: "Price update notification",
972
+ schema: import_zod.z.object({
973
+ symbol: import_zod.z.string(),
974
+ timestamp: import_zod.z.number(),
975
+ bid: import_zod.z.number(),
976
+ offer: import_zod.z.number(),
977
+ spread: import_zod.z.number(),
978
+ volume: import_zod.z.number()
979
+ })
980
+ },
981
+ () => ({
982
+ content: [
983
+ {
984
+ type: "text",
985
+ text: JSON.stringify({ symbol, ...data })
986
+ }
987
+ ]
988
+ })
989
+ );
990
+ }
1626
991
  );
1627
992
  }
1628
993
  });
@@ -1684,15 +1049,7 @@ var MCPRemote = class extends MCPBase {
1684
1049
  );
1685
1050
  return;
1686
1051
  }
1687
- try {
1688
- await transport.handleRequest(req, res, parsed);
1689
- } catch (error) {
1690
- this.logger?.log({
1691
- level: "error",
1692
- message: `Error handling request: ${error}`
1693
- });
1694
- throw error;
1695
- }
1052
+ await transport.handleRequest(req, res, parsed);
1696
1053
  });
1697
1054
  } else if (req.method === "GET" || req.method === "DELETE") {
1698
1055
  if (!sessionId || !transports[sessionId]) {
@@ -1701,20 +1058,8 @@ var MCPRemote = class extends MCPBase {
1701
1058
  return;
1702
1059
  }
1703
1060
  const transport = transports[sessionId];
1704
- try {
1705
- await transport.handleRequest(req, res);
1706
- } catch (error) {
1707
- this.logger?.log({
1708
- level: "error",
1709
- message: `Error handling ${req.method} request: ${error}`
1710
- });
1711
- throw error;
1712
- }
1061
+ await transport.handleRequest(req, res);
1713
1062
  } else {
1714
- this.logger?.log({
1715
- level: "error",
1716
- message: `Method not allowed: ${req.method}`
1717
- });
1718
1063
  res.writeHead(405);
1719
1064
  res.end("Method Not Allowed");
1720
1065
  }
@@ -1748,40 +1093,69 @@ var MCPRemote = class extends MCPBase {
1748
1093
  });
1749
1094
  return;
1750
1095
  }
1751
- const toolHandlers = createToolHandlers(
1752
- this.parser,
1753
- this.verifiedOrders,
1754
- this.pendingRequests,
1755
- this.marketDataPrices
1096
+ this.mcpServer.tool(
1097
+ "tools/list",
1098
+ {
1099
+ description: "List available tools",
1100
+ schema: import_zod.z.object({})
1101
+ },
1102
+ async () => {
1103
+ return {
1104
+ content: [
1105
+ {
1106
+ type: "text",
1107
+ text: JSON.stringify(
1108
+ Object.entries(toolSchemas).map(([name, { description, schema }]) => ({
1109
+ name,
1110
+ description,
1111
+ inputSchema: schema
1112
+ }))
1113
+ )
1114
+ }
1115
+ ]
1116
+ };
1117
+ }
1756
1118
  );
1757
- Object.entries(toolSchemas).forEach(([name, { description, schema }]) => {
1758
- this.mcpServer?.registerTool(
1759
- name,
1760
- {
1761
- description,
1762
- inputSchema: jsonSchemaToZod(schema)
1763
- },
1764
- async (args) => {
1765
- const handler = toolHandlers[name];
1766
- if (!handler) {
1767
- return {
1768
- content: [
1769
- {
1770
- type: "text",
1771
- text: `Tool not found: ${name}`
1772
- }
1773
- ],
1774
- isError: true
1775
- };
1776
- }
1777
- const result = await handler(args);
1119
+ this.mcpServer.tool(
1120
+ "tools/call",
1121
+ {
1122
+ description: "Call a tool",
1123
+ schema: import_zod.z.object({
1124
+ name: import_zod.z.string(),
1125
+ arguments: import_zod.z.any(),
1126
+ _meta: import_zod.z.object({
1127
+ progressToken: import_zod.z.number()
1128
+ }).optional()
1129
+ })
1130
+ },
1131
+ async (request) => {
1132
+ const { name, arguments: args } = request;
1133
+ const toolHandlers = createToolHandlers(
1134
+ this.parser,
1135
+ this.verifiedOrders,
1136
+ this.pendingRequests,
1137
+ this.marketDataPrices
1138
+ );
1139
+ const handler = toolHandlers[name];
1140
+ if (!handler) {
1778
1141
  return {
1779
- content: result.content,
1780
- isError: result.isError
1142
+ content: [
1143
+ {
1144
+ type: "text",
1145
+ text: `Tool not found: ${name}`,
1146
+ uri: name
1147
+ }
1148
+ ],
1149
+ isError: true
1781
1150
  };
1782
1151
  }
1783
- );
1784
- });
1152
+ const result = await handler(args);
1153
+ return {
1154
+ content: result.content,
1155
+ isError: result.isError
1156
+ };
1157
+ }
1158
+ );
1785
1159
  }
1786
1160
  };
1787
1161
  // Annotate the CommonJS export names for ESM import in node: