Skip to main content
Glama
Long0308

VN Stock API MCP Server

by Long0308

analyze_doji_pattern

Identify Doji candlestick patterns in Vietnamese stock charts to detect market indecision and potential trend reversals for technical analysis.

Instructions

Analyze Doji candlestick patterns in stock price charts. Doji patterns indicate market indecision and potential trend reversals. Detects various types of Doji patterns including Standard Doji, Long-legged Doji, Dragonfly Doji, Gravestone Doji, and Four Price Doji.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
symbolYesStock symbol to analyze (e.g., 'VIC', 'VNM', 'VCB')
periodNoTime period for analysis: '1D' (daily), '1W' (weekly), '1M' (monthly). Default: '1D'1D
daysNoNumber of days to analyze (default: 30, max: 100). Used to detect Doji patterns in historical data.
thresholdNoThreshold for Doji detection as percentage of price range (default: 0.1 = 0.1%). Lower values detect more Doji patterns.

Implementation Reference

  • src/index.ts:180-209 (registration)
    Tool registration with name 'analyze_doji_pattern', description, and input schema definition.
      name: "analyze_doji_pattern",
      description:
        "Analyze Doji candlestick patterns in stock price charts. Doji patterns indicate market indecision and potential trend reversals. Detects various types of Doji patterns including Standard Doji, Long-legged Doji, Dragonfly Doji, Gravestone Doji, and Four Price Doji.",
      inputSchema: {
        type: "object",
        properties: {
          symbol: {
            type: "string",
            description: "Stock symbol to analyze (e.g., 'VIC', 'VNM', 'VCB')",
          },
          period: {
            type: "string",
            enum: ["1D", "1W", "1M"],
            description: "Time period for analysis: '1D' (daily), '1W' (weekly), '1M' (monthly). Default: '1D'",
            default: "1D",
          },
          days: {
            type: "number",
            description: "Number of days to analyze (default: 30, max: 100). Used to detect Doji patterns in historical data.",
            default: 30,
          },
          threshold: {
            type: "number",
            description: "Threshold for Doji detection as percentage of price range (default: 0.1 = 0.1%). Lower values detect more Doji patterns.",
            default: 0.1,
          },
        },
        required: ["symbol"],
      },
    },
  • src/index.ts:235-236 (registration)
    Handler registration in the switch statement for CallToolRequest.
    case "analyze_doji_pattern":
      return await this.analyzeDojiPattern(args as any);
  • Main handler function that orchestrates fetching historical stock data, detecting Doji patterns, classifying them, and generating analysis report.
    private async analyzeDojiPattern(args: {
      symbol: string;
      period?: "1D" | "1W" | "1M";
      days?: number;
      threshold?: number;
    }) {
      const { symbol, period = "1D", days = 30, threshold = 0.1 } = args;
      const maxDays = Math.min(days, 100);
      const symbolUpper = symbol.trim().toUpperCase();
    
      try {
        // Try to get OHLC data from FireAnt API
        let candles: any[] = [];
    
        try {
          // FireAnt API endpoint for historical data
          const apiUrl = `https://restv2.fireant.vn/symbols/${symbolUpper}/bars?resolution=${period}&from=${Date.now() - maxDays * 24 * 60 * 60 * 1000}&to=${Date.now()}`;
          const response = await fetch(apiUrl, {
            headers: {
              "User-Agent": "Mozilla/5.0",
              Accept: "application/json",
            },
          });
    
          if (response.ok) {
            const data: any = await response.json();
            candles = Array.isArray(data) ? data : data.data || data.bars || [];
          }
        } catch (error) {
          // If API fails, provide guidance
          return {
            content: [
              {
                type: "text",
                text: JSON.stringify(
                  {
                    symbol: symbolUpper,
                    error: "Unable to fetch OHLC data from FireAnt API",
                    note: "FireAnt API may require authentication. Please check FireAnt API documentation or use Firecrawl to scrape from https://www.fireant.vn",
                    suggestion: "You can use Firecrawl MCP server to scrape historical price data from FireAnt website, then analyze Doji patterns manually.",
                    dojiPatterns: this.getDojiPatternInfo(),
                  },
                  null,
                  2
                ),
              },
            ],
            isError: true,
          };
        }
    
        if (candles.length === 0) {
          return {
            content: [
              {
                type: "text",
                text: JSON.stringify(
                  {
                    symbol: symbolUpper,
                    error: "No price data available",
                    note: "Unable to fetch historical price data. Please check if the symbol is correct or try using Firecrawl to scrape data.",
                    dojiPatterns: this.getDojiPatternInfo(),
                  },
                  null,
                  2
                ),
              },
            ],
            isError: true,
          };
        }
    
        // Analyze Doji patterns
        const dojiPatterns = this.detectDojiPatterns(candles, threshold);
        const analysis = this.analyzeDojiSignificance(dojiPatterns, candles);
    
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(
                {
                  symbol: symbolUpper,
                  period: period,
                  analysisPeriod: `${maxDays} days`,
                  totalCandles: candles.length,
                  dojiPatternsFound: dojiPatterns.length,
                  patterns: dojiPatterns,
                  analysis: analysis,
                  interpretation: this.getDojiInterpretation(dojiPatterns),
                  note: "Doji patterns indicate market indecision. Always combine with other technical indicators for better trading decisions.",
                },
                null,
                2
              ),
            },
          ],
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(
                {
                  error: error instanceof Error ? error.message : String(error),
                  symbol: symbolUpper,
                  note: "Unable to analyze Doji patterns. Please ensure you have access to price data.",
                  dojiPatterns: this.getDojiPatternInfo(),
                },
                null,
                2
              ),
            },
          ],
          isError: true,
        };
      }
    }
  • Helper function to detect Doji patterns in OHLC candle data.
    private detectDojiPatterns(candles: any[], threshold: number): any[] {
      const dojiPatterns: any[] = [];
    
      for (let i = 0; i < candles.length; i++) {
        const candle = candles[i];
        const open = parseFloat(candle.open || candle.o || 0);
        const high = parseFloat(candle.high || candle.h || 0);
        const low = parseFloat(candle.low || candle.l || 0);
        const close = parseFloat(candle.close || candle.c || 0);
        const timestamp = candle.timestamp || candle.time || candle.date || i;
    
        if (open === 0 || high === 0 || low === 0 || close === 0) continue;
    
        const bodySize = Math.abs(close - open);
        const totalRange = high - low;
        const upperShadow = high - Math.max(open, close);
        const lowerShadow = Math.min(open, close) - low;
    
        // Threshold for Doji detection (body should be very small compared to range)
        const dojiThreshold = (totalRange * threshold) / 100;
    
        if (bodySize <= dojiThreshold && totalRange > 0) {
          const dojiType = this.classifyDojiType(
            bodySize,
            upperShadow,
            lowerShadow,
            totalRange
          );
    
          dojiPatterns.push({
            index: i,
            date: new Date(timestamp).toISOString(),
            open: open,
            high: high,
            low: low,
            close: close,
            bodySize: bodySize,
            totalRange: totalRange,
            upperShadow: upperShadow,
            lowerShadow: lowerShadow,
            type: dojiType.type,
            description: dojiType.description,
            significance: dojiType.significance,
          });
        }
      }
    
      return dojiPatterns;
    }
  • Helper function to classify detected Doji patterns into specific types with descriptions and significance.
    private classifyDojiType(
      bodySize: number,
      upperShadow: number,
      lowerShadow: number,
      totalRange: number
    ): { type: string; description: string; significance: string } {
      const bodyRatio = bodySize / totalRange;
      const upperRatio = upperShadow / totalRange;
      const lowerRatio = lowerShadow / totalRange;
    
      // Four Price Doji: Open = High = Low = Close
      if (bodySize === 0 && totalRange === 0) {
        return {
          type: "Four Price Doji",
          description: "Extremely rare pattern where Open = High = Low = Close",
          significance: "Very strong indecision, extremely rare occurrence",
        };
      }
    
      // Standard Doji: Small body with shadows on both sides
      if (bodyRatio < 0.1 && upperRatio > 0.2 && lowerRatio > 0.2) {
        return {
          type: "Standard Doji",
          description: "Open and close are nearly equal with shadows on both sides",
          significance: "Market indecision, potential trend reversal",
        };
      }
    
      // Long-legged Doji: Small body with very long shadows
      if (
        bodyRatio < 0.1 &&
        upperRatio > 0.3 &&
        lowerRatio > 0.3 &&
        totalRange > 0
      ) {
        return {
          type: "Long-legged Doji",
          description: "Small body with very long upper and lower shadows",
          significance: "High volatility and strong indecision, potential reversal",
        };
      }
    
      // Dragonfly Doji: Small body at top, long lower shadow
      if (
        bodyRatio < 0.1 &&
        lowerRatio > 0.6 &&
        upperRatio < 0.1 &&
        totalRange > 0
      ) {
        return {
          type: "Dragonfly Doji",
          description: "Open and close near the high, with long lower shadow",
          significance: "Bullish reversal signal, especially after downtrend",
        };
      }
    
      // Gravestone Doji: Small body at bottom, long upper shadow
      if (
        bodyRatio < 0.1 &&
        upperRatio > 0.6 &&
        lowerRatio < 0.1 &&
        totalRange > 0
      ) {
        return {
          type: "Gravestone Doji",
          description: "Open and close near the low, with long upper shadow",
          significance: "Bearish reversal signal, especially after uptrend",
        };
      }
    
      // Generic Doji
      return {
        type: "Doji",
        description: "Open and close are nearly equal",
        significance: "Market indecision, watch for confirmation",
      };
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It describes what the tool does (detects Doji patterns) and lists pattern types, but lacks critical behavioral details: it doesn't specify output format, whether it's read-only or mutative, error handling, rate limits, or authentication needs. For a tool with no annotations, this is a significant gap in transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded: the first sentence states the core purpose, followed by explanatory context. It avoids redundancy and wastes no words, though it could be slightly more structured (e.g., separating pattern types into a list). Overall, it's efficient and clear.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (technical analysis tool with 4 parameters) and lack of annotations and output schema, the description is incomplete. It doesn't explain what the tool returns (e.g., a list of detected patterns with details), error conditions, or practical usage constraints. For a tool with no output schema, the description should compensate by detailing return values, but it doesn't.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds no parameter-specific information beyond what's in the schema (e.g., it doesn't explain how 'threshold' relates to pattern detection in practice). With high schema coverage, the baseline is 3, as the description doesn't compensate with additional semantic value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Analyze Doji candlestick patterns in stock price charts.' It specifies the verb ('analyze') and resource ('Doji candlestick patterns in stock price charts'), and distinguishes it from sibling tools by focusing on technical analysis rather than data retrieval or news. However, it doesn't explicitly differentiate from potential similar analysis tools (none in the sibling list), so it's not a perfect 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It mentions that 'Doji patterns indicate market indecision and potential trend reversals,' which implies usage for technical analysis, but offers no explicit when/when-not instructions, prerequisites, or comparisons to sibling tools like get_stock_price_fireant or search_vn_stock_api. This leaves the agent with minimal context for tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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/Long0308/vn-stock-api-mcp'

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