Skip to main content
Glama
market.py28.8 kB
"""Market trading tools for TWSE data.""" from utils import TWSEAPIClient def register_tools(mcp): """Register market trading tools with the MCP instance.""" @mcp.tool def get_stocks_no_price_change_first_five_days() -> str: """Get stocks with no price change in the first five trading days.""" try: data = TWSEAPIClient.get_data("/exchangeReport/TWT88U") if not data: return "目前沒有上市個股首五日無漲跌幅資料。" result = f"共有 {len(data)} 筆上市個股首五日無漲跌幅資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") reference_price = item.get("參考價", "N/A") result += f"- {stock_name} ({stock_code}): 參考價 {reference_price}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_financial_program_abnormal_recommendations() -> str: """Get stocks abnormally recommended in financial programs.""" try: data = TWSEAPIClient.get_data("/Announcement/BFZFZU_T") if not data: return "目前沒有投資理財節目異常推介個股資料。" result = f"共有 {len(data)} 筆投資理財節目異常推介個股資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") program_name = item.get("節目名稱", "N/A") result += f"- {stock_name} ({stock_code}): {program_name}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_daily_day_trading_targets() -> str: """Get daily day trading targets and statistics.""" try: data = TWSEAPIClient.get_data("/exchangeReport/TWTB4U") if not data: return "目前沒有上市股票每日當日沖銷交易標的及統計資料。" result = f"共有 {len(data)} 筆上市股票每日當日沖銷交易標的及統計資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") day_trading_volume = item.get("當日沖銷交易量", "N/A") result += f"- {stock_name} ({stock_code}): 當日沖銷交易量 {day_trading_volume}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_suspended_day_trading_announcement() -> str: """Get announcement of suspended buy-sell-same-day trading targets.""" try: data = TWSEAPIClient.get_data("/exchangeReport/TWTBAU1") if not data: return "目前沒有集中市場暫停先賣後買當日沖銷交易標的預告表資料。" result = f"共有 {len(data)} 筆集中市場暫停先賣後買當日沖銷交易標的預告表資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") suspension_date = item.get("暫停日期", "N/A") result += f"- {stock_name} ({stock_code}): 暫停日期 {suspension_date}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_suspended_day_trading_history() -> str: """Get historical query of suspended buy-sell-same-day trading.""" try: data = TWSEAPIClient.get_data("/exchangeReport/TWTBAU2") if not data: return "目前沒有集中市場暫停先賣後買當日沖銷交易歷史查詢資料。" result = f"共有 {len(data)} 筆集中市場暫停先賣後買當日沖銷交易歷史查詢資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") suspension_date = item.get("暫停日期", "N/A") result += f"- {stock_name} ({stock_code}): 暫停日期 {suspension_date}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_cross_market_trading_info() -> str: """Get daily cross-market trading information for listed and OTC stocks.""" try: data = TWSEAPIClient.get_data("/exchangeReport/MI_INDEX4") if not data: return "目前沒有每日上市上櫃跨市場成交資訊。" result = f"共有 {len(data)} 筆每日上市上櫃跨市場成交資訊:\n\n" for item in data[:20]: # Limit to first 20 for readability date = item.get("日期", "N/A") market = item.get("市場別", "N/A") volume = item.get("成交量", "N/A") result += f"- {date} {market}: 成交量 {volume}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_top_20_volume_stocks() -> str: """Get top 20 stocks by trading volume in the centralized market. Returns information including: - Date: Trading date - Rank: Volume ranking - Code: Stock code - Name: Stock name - TradeVolume: Trading volume - Transaction: Transaction count - OpeningPrice: Opening price - HighestPrice: Highest price - LowestPrice: Lowest price - ClosingPrice: Closing price - Dir: Direction (+/-) - Change: Price change """ try: data = TWSEAPIClient.get_data("/exchangeReport/MI_INDEX20") if not data: return "目前沒有集中市場每日成交量前二十名證券資料。" # Get the date from first item date = data[0].get("Date", "N/A") if data else "N/A" result = f"集中市場每日成交量前二十名證券 (日期: {date}):\n\n" for item in data[:20]: rank = item.get("Rank", "N/A") code = item.get("Code", "N/A") name = item.get("Name", "N/A") volume = item.get("TradeVolume", "N/A") transaction = item.get("Transaction", "N/A") closing_price = item.get("ClosingPrice", "N/A") direction = item.get("Dir", "") change = item.get("Change", "N/A") # Format price change with direction change_str = f"{direction}{change}" if direction and change != "N/A" else change result += f"{rank}. {name} ({code})\n" result += f" 成交量: {volume} | 成交筆數: {transaction}\n" result += f" 收盤價: {closing_price} | 漲跌: {change_str}\n\n" return result.strip() except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_odd_lot_trading_quotes() -> str: """Get odd-lot trading quotes in the centralized market.""" try: data = TWSEAPIClient.get_data("/exchangeReport/TWT53U") if not data: return "目前沒有集中市場零股交易行情單資料。" result = f"共有 {len(data)} 筆集中市場零股交易行情單資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") price = item.get("成交價", "N/A") volume = item.get("成交量", "N/A") result += f"- {stock_name} ({stock_code}): 成交價 {price}, 成交量 {volume}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_suspended_trading_stocks() -> str: """Get stocks suspended from trading in the centralized market.""" try: data = TWSEAPIClient.get_data("/exchangeReport/TWTAWU") if not data: return "目前沒有集中市場暫停交易證券資料。" result = f"共有 {len(data)} 筆集中市場暫停交易證券資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") suspension_reason = item.get("暫停原因", "N/A") result += f"- {stock_name} ({stock_code}): {suspension_reason}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_after_hours_trading() -> str: """Get after-hours fixed-price trading in the centralized market.""" try: data = TWSEAPIClient.get_data("/exchangeReport/BFT41U") if not data: return "目前沒有集中市場盤後定價交易資料。" result = f"共有 {len(data)} 筆集中市場盤後定價交易資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") price = item.get("成交價", "N/A") volume = item.get("成交量", "N/A") result += f"- {stock_name} ({stock_code}): 成交價 {price}, 成交量 {volume}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_margin_loan_restrictions_announcement() -> str: """Get announcement of margin loan and short sale restrictions.""" try: data = TWSEAPIClient.get_data("/exchangeReport/BFI84U") if not data: return "目前沒有集中市場停資停券預告表資料。" result = f"共有 {len(data)} 筆集中市場停資停券預告表資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") restriction_type = item.get("限制類別", "N/A") result += f"- {stock_name} ({stock_code}): {restriction_type}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_block_trades_daily() -> str: """Get daily block trade volume and value statistics.""" try: data = TWSEAPIClient.get_data("/block/BFIAUU_d") if not data: return "目前沒有集中市場鉅額交易日成交量值統計資料。" result = f"共有 {len(data)} 筆集中市場鉅額交易日成交量值統計資料:\n\n" for item in data[:20]: # Limit to first 20 for readability date = item.get("日期", "N/A") trade_count = item.get("交易筆數", "N/A") total_value = item.get("總成交金額", "N/A") result += f"- {date}: {trade_count} 筆, 總成交金額 {total_value}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_block_trades_monthly() -> str: """Get monthly block trade volume and value statistics.""" try: data = TWSEAPIClient.get_data("/block/BFIAUU_m") if not data: return "目前沒有集中市場鉅額交易月成交量值統計資料。" result = f"共有 {len(data)} 筆集中市場鉅額交易月成交量值統計資料:\n\n" for item in data[:20]: # Limit to first 20 for readability month = item.get("月份", "N/A") trade_count = item.get("交易筆數", "N/A") total_value = item.get("總成交金額", "N/A") result += f"- {month}: {trade_count} 筆, 總成交金額 {total_value}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_block_trades_yearly() -> str: """Get yearly block trade volume and value statistics.""" try: data = TWSEAPIClient.get_data("/block/BFIAUU_y") if not data: return "目前沒有集中市場鉅額交易年成交量值統計資料。" result = f"共有 {len(data)} 筆集中市場鉅額交易年成交量值統計資料:\n\n" for item in data[:20]: # Limit to first 20 for readability year = item.get("年度", "N/A") trade_count = item.get("交易筆數", "N/A") total_value = item.get("總成交金額", "N/A") result += f"- {year}: {trade_count} 筆, 總成交金額 {total_value}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_first_listed_foreign_stocks_daily() -> str: """Get daily trading volume and value of first-listed foreign stocks.""" try: data = TWSEAPIClient.get_data("/exchangeReport/STOCK_FIRST") if not data: return "目前沒有每日第一上市外國股票成交量值資料。" result = f"共有 {len(data)} 筆每日第一上市外國股票成交量值資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") volume = item.get("成交量", "N/A") value = item.get("成交金額", "N/A") result += f"- {stock_name} ({stock_code}): 成交量 {volume}, 成交金額 {value}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_securities_trading_changes() -> str: """Get securities trading method changes in the centralized market.""" try: data = TWSEAPIClient.get_data("/exchangeReport/TWT85U") if not data: return "目前沒有集中市場證券變更交易資料。" result = f"共有 {len(data)} 筆集中市場證券變更交易資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") change_type = item.get("變更類別", "N/A") result += f"- {stock_name} ({stock_code}): {change_type}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_valuation_ratios_by_date() -> str: """Get stock P/E ratio, dividend yield and P/B ratio by date query.""" try: data = TWSEAPIClient.get_data("/exchangeReport/BWIBBU_d") if not data: return "目前沒有上市個股日本益比、殖利率及股價淨值比(依日期查詢)資料。" result = f"共有 {len(data)} 筆上市個股日本益比、殖利率及股價淨值比(依日期查詢)資料:\n\n" for item in data[:20]: # Limit to first 20 for readability date = item.get("日期", "N/A") stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") pe_ratio = item.get("本益比", "N/A") result += f"- {date} {stock_name} ({stock_code}): 本益比 {pe_ratio}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_stock_price_changes() -> str: """Get stock price increase/decrease range.""" try: data = TWSEAPIClient.get_data("/exchangeReport/TWT84U") if not data: return "目前沒有上市個股股價升降幅度資料。" result = f"共有 {len(data)} 筆上市個股股價升降幅度資料:\n\n" for item in data[:20]: # Limit to first 20 for readability stock_code = item.get("證券代號", "N/A") stock_name = item.get("證券名稱", "N/A") price_change = item.get("漲跌幅", "N/A") result += f"- {stock_name} ({stock_code}): 漲跌幅 {price_change}%\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_market_gain_loss_statistics() -> str: """Get market statistics of rising and falling securities. Returns statistics including: - 出表日期: Report date (ROC calendar format) - 類型: Type (整體市場/股票/etc.) - 上漲: Number of rising securities - 漲停: Number of securities at upper limit - 下跌: Number of falling securities - 跌停: Number of securities at lower limit - 持平: Number of unchanged securities - 未成交: Number of non-traded securities - 無比價: Number of securities without comparison """ try: data = TWSEAPIClient.get_data("/opendata/twtazu_od") if not data: return "目前沒有集中市場漲跌證券數統計表資料。" result = f"集中市場漲跌證券數統計表 (共 {len(data)} 筆):\n\n" for item in data: date = item.get("出表日期", "N/A") category = item.get("類型", "N/A") rising = item.get("上漲", "N/A") limit_up = item.get("漲停", "N/A") falling = item.get("下跌", "N/A") limit_down = item.get("跌停", "N/A") unchanged = item.get("持平", "N/A") no_trade = item.get("未成交", "N/A") no_comparison = item.get("無比價", "N/A") result += f"【{category}】 日期: {date}\n" result += f" 上漲: {rising} 家 (漲停: {limit_up})\n" result += f" 下跌: {falling} 家 (跌停: {limit_down})\n" result += f" 持平: {unchanged} 家\n" result += f" 未成交: {no_trade} 家\n" result += f" 無比價: {no_comparison} 家\n\n" return result.strip() except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_abnormal_accumulated_notice_stocks() -> str: """Get stocks with abnormal accumulated notice counts. Returns information including: - Number: Record number (0 means no data) - Code: Stock code - Name: Stock name - RecentlyMetAttentionSecuritiesCriteria: Recently met attention securities criteria """ try: data = TWSEAPIClient.get_data("/announcement/notetrans") if not data: return "目前沒有集中市場公布注意累計次數異常資訊資料。" # Filter out empty records (Number="0" with empty Code) valid_data = [item for item in data if item.get("Code", "") != ""] if not valid_data: return "目前沒有集中市場公布注意累計次數異常資訊資料。" result = f"共有 {len(valid_data)} 筆集中市場公布注意累計次數異常資訊資料:\n\n" for item in valid_data[:20]: # Limit to first 20 for readability number = item.get("Number", "N/A") code = item.get("Code", "N/A") name = item.get("Name", "N/A") criteria = item.get("RecentlyMetAttentionSecuritiesCriteria", "N/A") result += f"{number}. {name} ({code})\n" result += f" 符合注意標準: {criteria}\n\n" if len(valid_data) > 20: result += f"... 還有 {len(valid_data) - 20} 筆資料\n" return result.strip() except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_today_notice_stocks() -> str: """Get stocks announced as notice stocks today. Returns information including: - Number: Record number (0 means no data) - Code: Stock code - Name: Stock name - NumberOfAnnouncement: Number of announcements - TradingInfoForAttention: Trading information for attention - Date: Announcement date - ClosingPrice: Closing price - PE: P/E ratio """ try: data = TWSEAPIClient.get_data("/announcement/notice") if not data: return "目前沒有集中市場當日公布注意股票資料。" # Filter out empty records (Number="0" with empty Code) valid_data = [item for item in data if item.get("Code", "") != ""] if not valid_data: return "目前沒有集中市場當日公布注意股票資料。" result = f"共有 {len(valid_data)} 筆集中市場當日公布注意股票資料:\n\n" for item in valid_data[:20]: # Limit to first 20 for readability number = item.get("Number", "N/A") code = item.get("Code", "N/A") name = item.get("Name", "N/A") announcement_count = item.get("NumberOfAnnouncement", "N/A") trading_info = item.get("TradingInfoForAttention", "N/A") date = item.get("Date", "N/A") closing_price = item.get("ClosingPrice", "N/A") pe_ratio = item.get("PE", "N/A") result += f"{number}. {name} ({code})\n" result += f" 公布次數: {announcement_count} | 日期: {date}\n" result += f" 收盤價: {closing_price} | 本益比: {pe_ratio}\n" result += f" 注意事項: {trading_info}\n\n" if len(valid_data) > 20: result += f"... 還有 {len(valid_data) - 20} 筆資料\n" return result.strip() except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_daily_market_trading_info() -> str: """Get daily market trading information in the centralized market.""" try: data = TWSEAPIClient.get_data("/exchangeReport/FMTQIK") if not data: return "目前沒有集中市場每日市場成交資訊。" result = f"共有 {len(data)} 筆集中市場每日市場成交資訊:\n\n" for item in data[:20]: # Limit to first 20 for readability date = item.get("Date", "N/A") trade_volume = item.get("TradeVolume", "N/A") trade_value = item.get("TradeValue", "N/A") transaction = item.get("Transaction", "N/A") taiex = item.get("TAIEX", "N/A") change = item.get("Change", "N/A") result += f"- {date}: 成交量 {trade_volume}, 成交金額 {trade_value}, 成交筆數 {transaction}, 加權指數 {taiex}, 漲跌 {change}\n" if len(data) > 20: result += f"\n... 還有 {len(data) - 20} 筆資料" return result except Exception as e: return f"查詢失敗: {str(e)}" @mcp.tool def get_daily_securities_lending_volume() -> str: """Get daily available volume for securities lending (margin trading).""" try: data = TWSEAPIClient.get_data("/SBL/TWT96U") if not data: return "目前沒有上市上櫃股票當日可借券賣出股數資料。" result = f"共有 {len(data)} 筆上市上櫃股票當日可借券賣出股數資料:\n\n" # Separate TWSE and GRETAI data twse_data = [item for item in data if item.get("TWSECode")] gretai_data = [item for item in data if item.get("GRETAICode")] if twse_data: result += "【上市股票】\n" for item in twse_data[:15]: # Limit to first 15 for readability stock_code = item.get("TWSECode", "N/A") available_volume = item.get("TWSEAvailableVolume", "N/A") result += f"- 股票代號 {stock_code}: 可借券賣出股數 {available_volume}\n" if len(twse_data) > 15: result += f"... 還有 {len(twse_data) - 15} 筆上市股票資料\n" if gretai_data: result += "\n【上櫃股票】\n" for item in gretai_data[:15]: # Limit to first 15 for readability stock_code = item.get("GRETAICode", "N/A") available_volume = item.get("GRETAIAvailableVolume", "N/A") result += f"- 股票代號 {stock_code}: 可借券賣出股數 {available_volume}\n" if len(gretai_data) > 15: result += f"... 還有 {len(gretai_data) - 15} 筆上櫃股票資料\n" return result except Exception as e: return f"查詢失敗: {str(e)}"

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/twjackysu/TWSEMCPServer'

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