UNPKG

@baguskto/saham

Version:

MCP Server untuk data saham Indonesia (IDX) - Implementasi Node.js/TypeScript

164 lines 7.23 kB
"use strict"; /** * Web scraping data source implementation (fallback) */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebScrapingSource = void 0; const axios_1 = __importDefault(require("axios")); const cheerio = __importStar(require("cheerio")); const base_1 = require("./base"); const config_1 = require("../config"); const logger_1 = require("../utils/logger"); const types_1 = require("../types"); class WebScrapingSource extends base_1.DataSource { userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'; constructor() { const dsConfig = config_1.config.getDataSources().webScraping; super('web_scraping', types_1.DataSourcePriority.MEDIUM, dsConfig.timeout); } async fetchPage(url) { const response = await axios_1.default.get(url, { timeout: this.timeout, headers: { 'User-Agent': this.userAgent, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1' } }); return cheerio.load(response.data); } async getStockInfo(ticker) { return this.makeRequest(`getStockInfo(${ticker})`, async () => { // This is a simplified implementation // In a real implementation, you would scrape from actual IDX or financial websites logger_1.logger.warn(`Web scraping for stock info not fully implemented for ${ticker}`); return null; }); } async getMarketOverview() { return this.makeRequest('getMarketOverview', async () => { try { // Try to scrape from Google Finance for IHSG const url = 'https://www.google.com/finance/quote/JKSE:IDX'; const $ = await this.fetchPage(url); // This is a basic implementation - the actual selectors would need to be // determined by inspecting the actual website structure const priceElement = $('[data-last-price]').first(); const changeElement = $('[data-last-change]').first(); if (priceElement.length === 0) { throw new Error('Could not find price data on page'); } const currentValue = parseFloat(priceElement.attr('data-last-price') || '0'); const changeText = changeElement.text() || ''; const change = parseFloat(changeText.replace(/[^\d.-]/g, '')) || 0; const changePercent = currentValue > 0 ? (change / (currentValue - change)) * 100 : 0; return { ihsgValue: currentValue, ihsgChange: change, ihsgChangePercent: changePercent, tradingVolume: 0, // Not available from basic scraping tradingValue: 0, marketStatus: this.getMarketStatus(), topGainers: [], // Would require additional scraping topLosers: [], foreignNetFlow: undefined, lastUpdated: new Date() }; } catch (error) { logger_1.logger.debug('Web scraping failed, returning null'); return null; } }); } getMarketStatus() { // Jakarta timezone (UTC+7) const now = new Date(); const jakartaTime = new Date(now.getTime() + (7 * 60 * 60 * 1000)); const day = jakartaTime.getUTCDay(); if (day === 0 || day === 6) { return 'closed'; } const hours = jakartaTime.getUTCHours(); const minutes = jakartaTime.getUTCMinutes(); const timeInMinutes = hours * 60 + minutes; const marketOpen = 9 * 60; const marketClose = 15 * 60 + 50; const preMarketStart = 8 * 60; if (timeInMinutes >= marketOpen && timeInMinutes <= marketClose) { return 'open'; } else if (timeInMinutes >= preMarketStart && timeInMinutes < marketOpen) { return 'pre-market'; } else { return 'closed'; } } async getHistoricalData(ticker, period) { return this.makeRequest(`getHistoricalData(${ticker}, ${period})`, async () => { // Historical data scraping is complex and would require // scraping from multiple pages or using different sources logger_1.logger.warn(`Web scraping for historical data not implemented for ${ticker}`); return null; }); } async getSectorPerformance() { return this.makeRequest('getSectorPerformance', async () => { // Sector performance would require scraping from IDX website // or other financial data providers logger_1.logger.warn('Web scraping for sector performance not implemented'); return null; }); } async searchStocks(query) { const result = await this.makeRequest(`searchStocks(${query})`, async () => { // Stock search would require scraping from IDX website // or implementing a local search from CSV data logger_1.logger.warn(`Web scraping for stock search not implemented for query: ${query}`); return []; }); return result || []; } } exports.WebScrapingSource = WebScrapingSource; //# sourceMappingURL=web-scraper.js.map