获取新加坡股票历史数据分析:使用接口文档的完整指南

0 阅读6分钟

获取新加坡股票历史数据分析:使用接口文档的完整指南

在金融数据分析和量化交易领域,获取准确、实时的股票历史数据是进行策略回测和市场分析的基础。新加坡作为亚洲重要的金融中心之一,其股票市场数据对于投资者和开发者具有重要价值。本文将详细介绍如何通过API获取新加坡股票的历史数据,并提供完整的Python实现示例。

二、准备工作

1. 获取API密钥

准备密钥

2. 安装必要依赖

pip install requests pandas matplotlib

三、新加坡市场数据获取

1. 确定新加坡市场标识

根据StockTV API文档,不同市场通过countryId参数进行区分。虽然公开文档中没有明确列出新加坡的countryId,但根据API的全球覆盖特性,新加坡市场是支持的。在实际使用中,您可以通过以下方式获取正确的标识符:

  • 查阅官方API文档
  • 联系技术支持获取准确参数

2. 核心接口说明

获取股票列表接口
import requests

def get_singapore_stocks(api_key, page_size=20, page=1):
    """
    获取新加坡股票列表
    """
    url = "https://api.stocktv.top/stock/stocks"
    params = {
        "key": api_key,
        "countryId": "SG",  # 新加坡市场标识(示例)
        "pageSize": page_size,
        "page": page
    }
    
    response = requests.get(url, params=params)
    if response.status_code == 200:
        return response.json()
    else:
        print(f"请求失败: {response.status_code}")
        return None
获取历史K线数据接口

这是获取股票历史数据的核心接口,支持多种时间周期:

def get_historical_kline(api_key, pid, interval="P1D", limit=100):
    """
    获取股票历史K线数据
    
    参数:
    - pid: 股票产品ID
    - interval: 时间间隔
        PT5M: 5分钟
        PT15M: 15分钟
        PT1H: 1小时
        P1D: 日线
        P1W: 周线
        P1M: 月线
    - limit: 数据条数
    """
    url = "https://api.stocktv.top/stock/kline"
    params = {
        "key": api_key,
        "pid": pid,
        "interval": interval,
        "limit": limit
    }
    
    response = requests.get(url, params=params)
    if response.status_code == 200:
        return response.json()
    else:
        print(f"请求失败: {response.status_code}")
        return None

四、完整示例:新加坡股票历史数据分析

下面是一个完整的Python示例,展示如何获取新加坡某只股票的历史数据并进行基本分析:

import requests
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime

class SingaporeStockAnalyzer:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = "https://api.stocktv.top"
        
    def get_stock_info(self, symbol):
        """查询特定股票信息"""
        url = f"{self.base_url}/stock/queryStocks"
        params = {
            "key": self.api_key,
            "symbol": symbol
        }
        
        response = requests.get(url, params=params)
        if response.status_code == 200:
            data = response.json()
            if data.get("code") == 200 and data.get("data"):
                return data["data"][0]
        return None
    
    def get_historical_data(self, pid, interval="P1D", days=30):
        """获取历史数据并转换为DataFrame"""
        url = f"{self.base_url}/stock/kline"
        params = {
            "key": self.api_key,
            "pid": pid,
            "interval": interval
        }
        
        response = requests.get(url, params=params)
        if response.status_code == 200:
            data = response.json()
            if data.get("code") == 200 and data.get("data"):
                # 转换为DataFrame
                df = pd.DataFrame(data["data"])
                
                # 转换时间戳
                df['date'] = pd.to_datetime(df['time'], unit='ms')
                df.set_index('date', inplace=True)
                
                # 保留核心字段
                df = df[['open', 'high', 'low', 'close', 'volume']]
                
                return df
        return None
    
    def calculate_technical_indicators(self, df):
        """计算技术指标"""
        # 移动平均线
        df['MA5'] = df['close'].rolling(window=5).mean()
        df['MA20'] = df['close'].rolling(window=20).mean()
        
        # 相对强弱指数(RSI)
        delta = df['close'].diff()
        gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
        rs = gain / loss
        df['RSI'] = 100 - (100 / (1 + rs))
        
        # 布林带
        df['Middle Band'] = df['close'].rolling(window=20).mean()
        df['Upper Band'] = df['Middle Band'] + 2 * df['close'].rolling(window=20).std()
        df['Lower Band'] = df['Middle Band'] - 2 * df['close'].rolling(window=20).std()
        
        return df
    
    def plot_stock_chart(self, df, title="新加坡股票价格走势"):
        """绘制股票图表"""
        fig, axes = plt.subplots(3, 1, figsize=(14, 10))
        
        # 价格走势图
        axes[0].plot(df.index, df['close'], label='收盘价', color='blue', linewidth=2)
        axes[0].plot(df.index, df['MA5'], label='5日均线', color='orange', linestyle='--')
        axes[0].plot(df.index, df['MA20'], label='20日均线', color='green', linestyle='--')
        axes[0].fill_between(df.index, df['Upper Band'], df['Lower Band'], alpha=0.2, color='gray')
        axes[0].set_title(f'{title} - 价格走势')
        axes[0].set_ylabel('价格')
        axes[0].legend()
        axes[0].grid(True, alpha=0.3)
        
        # 成交量图
        axes[1].bar(df.index, df['volume'], color='blue', alpha=0.6)
        axes[1].set_title('成交量')
        axes[1].set_ylabel('成交量')
        axes[1].grid(True, alpha=0.3)
        
        # RSI图
        axes[2].plot(df.index, df['RSI'], label='RSI', color='purple', linewidth=2)
        axes[2].axhline(y=70, color='red', linestyle='--', alpha=0.5, label='超买线')
        axes[2].axhline(y=30, color='green', linestyle='--', alpha=0.5, label='超卖线')
        axes[2].set_title('相对强弱指数(RSI)')
        axes[2].set_ylabel('RSI')
        axes[2].set_xlabel('日期')
        axes[2].legend()
        axes[2].grid(True, alpha=0.3)
        
        plt.tight_layout()
        plt.show()
    
    def generate_analysis_report(self, df):
        """生成分析报告"""
        latest_price = df['close'].iloc[-1]
        price_change = ((latest_price - df['close'].iloc[0]) / df['close'].iloc[0]) * 100
        
        avg_volume = df['volume'].mean()
        volatility = df['close'].pct_change().std() * 100
        
        report = {
            "分析期间": f"{df.index[0].date()}{df.index[-1].date()}",
            "数据点数": len(df),
            "最新收盘价": f"{latest_price:.2f}",
            "期间涨跌幅": f"{price_change:.2f}%",
            "平均日成交量": f"{avg_volume:,.0f}",
            "价格波动率": f"{volatility:.2f}%",
            "最高价": f"{df['high'].max():.2f}",
            "最低价": f"{df['low'].min():.2f}",
            "当前RSI": f"{df['RSI'].iloc[-1]:.2f}" if 'RSI' in df.columns else "N/A"
        }
        
        return report

# 使用示例
def main():
    # 替换为您的API密钥
    API_KEY = "YOUR_API_KEY_HERE"
    
    # 初始化分析器
    analyzer = SingaporeStockAnalyzer(API_KEY)
    
    # 示例:分析新加坡银行股(假设股票代码为DBS)
    stock_info = analyzer.get_stock_info("DBS")
    if stock_info:
        print(f"股票信息: {stock_info['name']} ({stock_info['symbol']})")
        print(f"最新价格: {stock_info['last']}")
        print(f"涨跌幅: {stock_info['chgPct']}%")
        
        # 获取历史数据
        historical_data = analyzer.get_historical_data(
            pid=stock_info['id'],
            interval="P1D",
            days=90
        )
        
        if historical_data is not None:
            # 计算技术指标
            analyzed_data = analyzer.calculate_technical_indicators(historical_data)
            
            # 生成分析报告
            report = analyzer.generate_analysis_report(analyzed_data)
            print("\n=== 分析报告 ===")
            for key, value in report.items():
                print(f"{key}: {value}")
            
            # 绘制图表
            analyzer.plot_stock_chart(analyzed_data, title=f"{stock_info['name']} 技术分析")
        else:
            print("无法获取历史数据")
    else:
        print("无法获取股票信息")

if __name__ == "__main__":
    main()

五、数据处理与存储建议

1. 数据缓存策略

由于股票数据更新频繁但某些数据变化不大,建议实现缓存机制:

import redis
import json
from datetime import timedelta

class StockDataCache:
    def __init__(self, redis_host='localhost', redis_port=6379):
        self.redis_client = redis.Redis(host=redis_host, port=redis_port, decode_responses=True)
    
    def get_cached_data(self, cache_key):
        """获取缓存数据"""
        cached = self.redis_client.get(cache_key)
        if cached:
            return json.loads(cached)
        return None
    
    def set_cache_data(self, cache_key, data, expiry_hours=1):
        """设置缓存数据"""
        self.redis_client.setex(
            cache_key,
            timedelta(hours=expiry_hours),
            json.dumps(data)
        )

2. 数据持久化

import sqlite3
import pandas as pd

class StockDataStorage:
    def __init__(self, db_path='stock_data.db'):
        self.conn = sqlite3.connect(db_path)
    
    def save_historical_data(self, symbol, df):
        """保存历史数据到数据库"""
        df['symbol'] = symbol
        df['created_at'] = pd.Timestamp.now()
        
        df.to_sql('historical_prices', self.conn, if_exists='append', index=False)
    
    def get_historical_data(self, symbol, start_date, end_date):
        """从数据库获取历史数据"""
        query = """
        SELECT * FROM historical_prices 
        WHERE symbol = ? AND date BETWEEN ? AND ?
        ORDER BY date
        """
        return pd.read_sql_query(query, self.conn, params=[symbol, start_date, end_date])

六、注意事项

  1. API限制:注意查看API的请求频率限制,避免过度请求导致被封禁
  2. 错误处理:妥善处理网络错误和API返回的错误信息
  3. 数据准确性:重要决策前应验证数据的准确性和时效性
  4. 密钥安全:妥善保管API密钥,不要在前端代码中暴露
  5. 时区处理:新加坡市场时间与北京时间相同,无需时区转换

七、总结

本文不构成任何投资建议。本文提供的代码示例和技术方案,可以帮助您快速上手新加坡股票历史数据的获取与分析。