Skip to main content
Glama
sammcj

Bybit MCP Server

by sammcj

get_ml_rsi

Calculate ML-enhanced RSI values using the K-Nearest Neighbors algorithm, providing adaptive overbought/oversold levels and improved accuracy through pattern recognition on Bybit MCP Server.

Instructions

Get ML-enhanced RSI using K-Nearest Neighbors algorithm for pattern recognition. Provides adaptive overbought/oversold levels and enhanced RSI values based on historical pattern similarity.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
categoryYesCategory of the instrument
featureCountNoNumber of features to use 1-5 (default: 3)
intervalYesKline interval
knnLookbackNoHistorical period for pattern matching (default: 100)
knnNeighborsNoNumber of neighbors for KNN algorithm (default: 5)
limitNoNumber of data points to return (default: 200)
mlWeightNoML influence weight 0-1 (default: 0.4)
rsiLengthNoRSI calculation period (default: 14)
smoothingMethodNoSmoothing method to apply (default: none)
symbolYesTrading pair symbol (e.g., 'BTCUSDT')

Implementation Reference

  • Main handler function that orchestrates the entire get_ml_rsi tool execution: input validation, data fetching, RSI calculation, feature extraction, KNN processing, smoothing, and response formatting.
    async toolCall(request: z.infer<typeof CallToolRequestSchema>): Promise<CallToolResult> {
      const startTime = Date.now()
    
      try {
        this.logInfo("Starting get_ml_rsi tool call")
    
        // Parse and validate input
        const validationResult = inputSchema.safeParse(request.params.arguments)
        if (!validationResult.success) {
          const errorDetails = validationResult.error.errors.map(err => ({
            field: err.path.join('.'),
            message: err.message,
            code: err.code
          }))
          throw new Error(`Invalid input: ${JSON.stringify(errorDetails)}`)
        }
    
        const args = validationResult.data
    
        // Fetch kline data
        const klineData = await this.fetchKlineData(args)
    
        if (klineData.length < args.rsiLength + args.knnLookback) {
          throw new Error(`Insufficient data. Need at least ${args.rsiLength + args.knnLookback} data points, got ${klineData.length}`)
        }
    
        // Calculate standard RSI
        const closePrices = klineData.map(k => k.close)
        const rsiValues = calculateRSI(closePrices, args.rsiLength)
    
        if (rsiValues.length === 0) {
          throw new Error("Failed to calculate RSI values")
        }
    
        // Extract features for all data points
        const allFeatures: FeatureVector[] = []
        for (let i = 0; i < klineData.length; i++) {
          const features = extractFeatures(klineData, i, rsiValues, args.featureCount, args.knnLookback)
          allFeatures.push(features || { rsi: rsiValues[i] || 0 })
        }
    
        // Configure KNN
        const knnConfig: KNNConfig = {
          neighbors: args.knnNeighbors,
          lookbackPeriod: args.knnLookback,
          mlWeight: args.mlWeight,
          featureCount: args.featureCount
        }
    
        // Apply KNN enhancement
        const knnResults = batchProcessKNN(rsiValues, allFeatures, klineData, knnConfig)
    
        // Apply smoothing if requested
        const smoothedResults = this.applySmoothingToResults(knnResults, rsiValues, args.smoothingMethod)
    
        // Format response data
        const responseData = this.formatMLRSIData(klineData, rsiValues, smoothedResults, args.limit)
    
        const calculationTime = Date.now() - startTime
    
        const response: MLRSIResponse = {
          symbol: args.symbol,
          interval: args.interval,
          data: responseData,
          metadata: {
            mlEnabled: true,
            featuresUsed: this.getFeatureNames(args.featureCount),
            smoothingApplied: args.smoothingMethod,
            calculationTime,
            rsiLength: args.rsiLength,
            knnConfig
          }
        }
    
        this.logInfo(`ML-RSI calculation completed in ${calculationTime}ms`)
        return this.formatResponse(response)
    
      } catch (error) {
        this.logInfo(`ML-RSI calculation failed: ${error instanceof Error ? error.message : String(error)}`)
        return this.handleError(error)
      }
    }
  • Zod schema defining and validating the input parameters for the get_ml_rsi tool.
    const inputSchema = z.object({
      symbol: z.string()
        .min(1, "Symbol is required")
        .regex(/^[A-Z0-9]+$/, "Symbol must contain only uppercase letters and numbers"),
      category: z.enum(["spot", "linear", "inverse"]),
      interval: z.enum(["1", "3", "5", "15", "30", "60", "120", "240", "360", "720", "D", "W", "M"]),
      rsiLength: z.number().min(2).max(50).optional().default(14),
      knnNeighbors: z.number().min(1).max(50).optional().default(5),
      knnLookback: z.number().min(20).max(500).optional().default(100),
      mlWeight: z.number().min(0).max(1).optional().default(0.4),
      featureCount: z.number().min(1).max(5).optional().default(3),
      smoothingMethod: z.enum(["none", "kalman", "alma", "double_ema"]).optional().default("none"),
      limit: z.number().min(50).max(1000).optional().default(200)
    })
  • MCP-standard tool definition object containing name, description, and JSON input schema for get_ml_rsi.
    toolDefinition: Tool = {
      name: this.name,
      description: "Get ML-enhanced RSI using K-Nearest Neighbors algorithm for pattern recognition. Provides adaptive overbought/oversold levels and enhanced RSI values based on historical pattern similarity.",
      inputSchema: {
        type: "object",
        properties: {
          symbol: {
            type: "string",
            description: "Trading pair symbol (e.g., 'BTCUSDT')",
            pattern: "^[A-Z0-9]+$"
          },
          category: {
            type: "string",
            description: "Category of the instrument",
            enum: ["spot", "linear", "inverse"]
          },
          interval: {
            type: "string",
            description: "Kline interval",
            enum: ["1", "3", "5", "15", "30", "60", "120", "240", "360", "720", "D", "W", "M"]
          },
          rsiLength: {
            type: "number",
            description: "RSI calculation period (default: 14)",
            minimum: 2,
            maximum: 50
          },
          knnNeighbors: {
            type: "number",
            description: "Number of neighbors for KNN algorithm (default: 5)",
            minimum: 1,
            maximum: 50
          },
          knnLookback: {
            type: "number",
            description: "Historical period for pattern matching (default: 100)",
            minimum: 20,
            maximum: 500
          },
          mlWeight: {
            type: "number",
            description: "ML influence weight 0-1 (default: 0.4)",
            minimum: 0,
            maximum: 1
          },
          featureCount: {
            type: "number",
            description: "Number of features to use 1-5 (default: 3)",
            minimum: 1,
            maximum: 5
          },
          smoothingMethod: {
            type: "string",
            description: "Smoothing method to apply (default: none)",
            enum: ["none", "kalman", "alma", "double_ema"]
          },
          limit: {
            type: "number",
            description: "Number of data points to return (default: 200)",
            minimum: 50,
            maximum: 1000
          }
        },
        required: ["symbol", "category", "interval"]
      }
    }
  • Dynamic loader that discovers, imports, instantiates, and validates all tool classes in src/tools (including GetMLRSI), adding valid ones to the tools array.
    export async function loadTools(): Promise<BaseToolImplementation[]> {
      try {
        const toolsPath = await findToolsPath()
        const files = await fs.readdir(toolsPath)
        const tools: BaseToolImplementation[] = []
    
        for (const file of files) {
          if (!isToolFile(file)) {
            continue
          }
    
          try {
            const modulePath = `file://${join(toolsPath, file)}`
            const { default: ToolClass } = await import(modulePath)
    
            if (!ToolClass || typeof ToolClass !== 'function') {
              console.warn(JSON.stringify({
                type: "warning",
                message: `Invalid tool class in ${file}`
              }))
              continue
            }
    
            const tool = new ToolClass()
    
            if (
              tool instanceof BaseToolImplementation &&
              tool.name &&
              tool.toolDefinition &&
              typeof tool.toolCall === "function"
            ) {
              tools.push(tool)
              console.info(JSON.stringify({
                type: "info",
                message: `Loaded tool: ${tool.name}`
              }))
            } else {
              console.warn(JSON.stringify({
                type: "warning",
                message: `Invalid tool implementation in ${file}`
              }))
            }
          } catch (error) {
            console.error(JSON.stringify({
              type: "error",
              message: `Error loading tool from ${file}: ${error instanceof Error ? error.message : String(error)}`
            }))
          }
        }
    
        return tools
      } catch (error) {
        console.error(JSON.stringify({
          type: "error",
          message: `Failed to load tools: ${error instanceof Error ? error.message : String(error)}`
        }))
        return []
      }
    }
  • src/index.ts:129-152 (registration)
    Initializes the MCP server, loads all tools via toolLoader (including get_ml_rsi), creates toolsMap for dispatch, sets up ListTools and CallTool request handlers that use the loaded tools.
    async function main() {
      try {
        // Validate environment configuration
        validateEnv()
    
        const tools = await loadTools()
        toolsMap = createToolsMap(tools)
    
        if (tools.length === 0) {
          console.log(JSON.stringify(formatJsonRpcMessage(
            "warning",
            "No tools were loaded. Server will start but may have limited functionality."
          )))
        } else {
          console.log(JSON.stringify(formatJsonRpcMessage(
            "info",
            `Loaded ${tools.length} tools: ${tools.map(t => t.name).join(", ")}`
          )))
        }
    
        const transport = new StdioServerTransport()
        await server.connect(transport)
    
        console.log(JSON.stringify(formatJsonRpcMessage(
Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sammcj/bybit-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server