印度股票实时行情API(低成本方案)

张开发
2026/4/9 8:49:11 15 分钟阅读

分享文章

印度股票实时行情API(低成本方案)
印度这个神奇的国度不仅有干净又卫生的街头美食它还是亚洲增速最快的资本市场之一无论是交易量、投资者增长还是IPO数量近年来都呈现出明显的上升趋势。针对印度市场的金融交易平台在近几年也越来越多我们将在本文介绍如何接入印度股票的实时行情如果您正在开发印度市场的股票交易平台一定不要错过!一、印度股票市场的基本情况我们先来看看印度股票市场的基本情况。印度证券交易委员会SEBI目前认可并监管的交易所总共有9家涵盖股权、衍生品、商品与国际证券等多个品类序号交易所简称主要类型总部/位置活跃度/特色总体市场份额1NSE股权衍生品孟买交易量最大衍生品霸主90%2BSE股权衍生品孟买历史最悠久上市公司最多10%3India INX国际/外币证券GIFT City全球投资者入口延长交易时段1%4NSE IFSC国际衍生品GIFT CityNSE的国际版1%5MSEI股权货币孟买第三大但份额微小1%6CSE股权有限加尔各答历史交易所基本不活跃近0%几乎无实质交易7MCX商品衍生品孟买金属能源主力商品衍生品市场~97-98%非股权不计入股票市场份额8NCDEX农产品商品孟买农业期货专营商品衍生品市场~2-3%农产品主力非股权9ICEX商品衍生品纳维孟买细分商品如钻石商品衍生品市场1%细分领域非股权对于需要接入印度市场数据的开发者与机构而言真正值得关注的核心交易所有两家NSE国家证券交易所印度交易量最大的交易所衍生品市场份额超过90%是绝大多数量化策略与实时数据需求的首选数据源。BSE孟买证券交易所成立于1875年是亚洲历史最悠久的交易所股权市场份额虽不及NSE但在部分品种上仍具不可替代性。截至2025年末BSE与NSE的上市公司数量合计超过5,300家交易量占据了印度接近98%的市场份额。NSE的衍生品日成交量更是长期位居全球前三妥妥的印度金融霸主。事实上NSE本身的估值一度高达4.7万亿卢比约合五百亿美元是印度最值钱的未上市公司在全球私人公司中排第10位。这两家交易所均采用印度标准时间ISTUTC5:30正常交易时段为周一至周五上午9:15至下午3:30预开盘阶段为9:00至9:15。二、印度股票实时行情API成本对比理论上开发者可以直接向NSE或BSE申请数据授权获取一手实时行情。但现实情况是这条路几乎只对大型机构开放。因为实在太贵了以下是直连两家交易所的核心费用对比费用项目NSEBSE股票L1实时年固定费约 176,640 元约 73,600 元期货与期权L1年固定费约 176,640 元约 36,800 元L2深度行情年固定费约 276,000 元约 73,600 元终端用户分发费月/用户约 603–809 元约 478–846 元备份链路约 14,720 元/条/年—GST增值税额外 18%额外 18%以上价格均已换算成人民币。仅NSE股票衍生品L1基础授权年度固定成本约在36万至58万元人民币之间叠加用户费、专线接入、GST及备份冗余实际全年总成本轻松突破百万元。BSE相对较低但L1股票实时授权也需7万至18万元起步。此外直连还要求申请方具备完整的企业资质、签署复杂的数据协议并自行搭建专线网络接入交易所数据中心。对于中小型团队或个人开发者而言这条路在经济上和操作上都几乎不现实。免费的第三方API如Yahoo Finance虽然存在但数据延迟普遍在10至15分钟以上而且频繁封IP根本无法满足实时交易或实时应用的需求。正是因为直连成本过高、门槛过硬市场上出现了一批专业的数据服务商他们统一采购交易所授权数据再以更合理的价格向下游开发者分发。这种模式在全球主要市场美股、欧股、港股早已成熟印度市场也正在走向同样的路径。三、Infoway API印度股票实时行情接口对大多数开发者来说Infoway API 是性价比最高的选择能在不承担高额成本的前提下快速搭建实时行情应用。Infoway API提供印度NSE交易所全部挂牌股票的实时行情数据约5300只个股。除了印度股票以外Infoway API还提供以下市场的实时数据A股、港股、美股、日本股票外汇货币对加密货币能源/贵金属期货Infoway API的接口使用非常简单先在官网注册账号注册完自动获得API Key → 点我注册在查询数据的时候需要带上API Key。下面来看看如何查询印度股票数据。3.1 成交明细成交明细Last trade查询地址https://data.infoway.io/india/batch_trade/{codes}需要在codes中传入对应的股票代码建议在我们的官网下载股票代码列表里面有所有的印度股票代码。下面是成交明细的请求示例import requests api_url https://data.infoway.io/india/batch_trade/INFY.IN # 设置请求头 headers { User-Agent: Mozilla/5.0, Accept: application/json, apiKey: YOUR_API_KEY_HERE } # 发送GET请求 response requests.get(api_url, headersheaders) # 输出结果 print(fHTTP code: {response.status_code}) print(fmessage: {response.text})成交明细端点返回如下内容{ s: INFY.IN, respList: [ { t: 1773037920, h: 1303.40, o: 1301.50, l: 1301.50, c: 1303.00, v: 15615.0, vw: 20342210.20, pc: 0.15%, pca: 1.90 } ] }字段说明字段说明s股票代码t秒时间戳UTC8p交易价格v成交量vw成交额td交易方向 1BUY 2SELL 0默认值3.2 实时K线K线请求地址https://data.infoway.io/india/v2/batch_kline/{klineType}/{klineNum}/{codes}参数说明klineType指的是K线的周期这里传入1返回1分钟K传入2返回5分钟K具体请查看K线查询教程。klineNum指的是需要返回的K线数量单只股票查询最多可一次要求返回500根最近的K线code代表股票代码示例查询InfoSys股票代码INFY.IN1分钟K线返回最近的10根import requests api_url https://data.infoway.io/india/v2/batch_kline/1/10/INFY.IN # 设置请求头 headers { User-Agent: Mozilla/5.0, Accept: application/json, apiKey: YOUR_API_KEY_HERE } # 发送GET请求 response requests.get(api_url, headersheaders) # 输出结果 print(fHTTP code: {response.status_code}) print(fmessage: {response.text})K线端点返回示例{ s: INFY.IN, respList: [ { t: 1773037920, h: 1303.40, o: 1301.50, l: 1301.50, c: 1303.00, v: 15615.0, vw: 20342210.20, pc: 0.15%, pca: 1.90 } ] }字段说明字段说明t秒时间戳UTC8h最高价o开盘价l最低价C收盘价v成交量vw成交额pc涨跌幅pca涨跌额3.3 盘口深度Infoway API提供全印度一档盘口深度请求地址https://data.infoway.io /india/batch_depth/{codes}同样在cdoes中传入股票代码即可import requests api_url https://data.infoway.io /india/batch_depth/INFY.IN # 设置请求头 headers { User-Agent: Mozilla/5.0, Accept: application/json, apiKey: YOUR_API_KEY_HERE } # 发送GET请求 response requests.get(api_url, headersheaders) # 输出结果 print(fHTTP code: {response.status_code}) print(fmessage: {response.text})盘口端点返回示例{ s: INFY.IN, t: 1773037524808, a: [ [ 1302.0, ], [ 1.0, ] ], b: [ [ 1301.9, ], [ 172.0, ] ] }a为买盘包含买一价和买一量b为卖盘包含卖一价和卖一量。3.4 WebSocket订阅全印度股票实时行情Infoway API支持WebSocket订阅可订阅全印度市场的实时K线、实时成交、以及实时盘口非常适合交易所用户。下面WebSocket代码示例包含断线重连机制import asyncio import json import uuid import logging from typing import Optional import websockets from websockets.exceptions import ConnectionClosed, WebSocketException # 配置日志 logging.basicConfig( levellogging.INFO, format%(asctime)s - %(name)s - %(levelname)s - %(message)s, handlers[logging.StreamHandler()] ) logger logging.getLogger(websocket-client) class CryptoWebsocketClient: 加密货币行情WebSocket客户端对等Java版本逻辑 def __init__(self, api_key: str, business: str crypto): # WebSocket连接配置 self.ws_url fwss://data.infoway.io/ws?businessindiaapikeyYourAPIKey # 核心状态 self.ws: Optional[websockets.WebSocketClientProtocol] None self.is_connected False self.reconnect_interval 10 # 重连间隔秒 self.heartbeat_interval 30 # 心跳间隔秒 # 任务对象用于管理异步任务 self.reconnect_task: Optional[asyncio.Task] None self.heartbeat_task: Optional[asyncio.Task] None async def connect(self) - None: 建立WebSocket连接 try: # 关闭旧连接防止连接泄露 if self.ws and not self.ws.closed: await self.ws.close() # 建立新连接 self.ws await websockets.connect(self.ws_url) self.is_connected True logger.info(fWebSocket连接成功地址: {self.ws_url}) # 连接成功后启动订阅和心跳 await self._send_all_subscribe_requests() self._start_heartbeat_task() except WebSocketException as e: self.is_connected False logger.error(fWebSocket连接失败: {str(e)}) raise async def _send_all_subscribe_requests(self) - None: 发送所有订阅请求成交明细、盘口、K线 if not self.ws or self.ws.closed: logger.error(连接未建立无法发送订阅请求) return try: # 1. 订阅实时成交明细协议号10000 await self._send_trade_subscribe() await asyncio.sleep(5) # 间隔5秒 # 2. 订阅实时盘口数据协议号10003 await self._send_depth_subscribe() await asyncio.sleep(5) # 间隔5秒 # 3. 订阅1分钟K线数据协议号10006 await self._send_kline_subscribe() except Exception as e: logger.error(f发送订阅请求失败: {str(e)}) raise def _generate_trace_id(self) - str: 生成唯一trace ID对等Java的UUID return str(uuid.uuid4()) async def _send_trade_subscribe(self) - None: 发送实时成交明细订阅请求 subscribe_msg { code: 10000, trace: self._generate_trace_id(), data: {codes: INFY.IN} } await self.ws.send(json.dumps(subscribe_msg)) logger.info(f发送成交明细订阅请求: {subscribe_msg}) async def _send_depth_subscribe(self) - None: 发送实时盘口数据订阅请求 subscribe_msg { code: 10003, trace: self._generate_trace_id(), data: {codes: INFY.IN} } await self.ws.send(json.dumps(subscribe_msg)) logger.info(f发送盘口数据订阅请求: {subscribe_msg}) async def _send_kline_subscribe(self) - None: 发送1分钟K线数据订阅请求 subscribe_msg { code: 10006, trace: self._generate_trace_id(), data: { arr: [ {type: 1, codes: INFY.IN} # type1 表示1分钟K线 ] } } await self.ws.send(json.dumps(subscribe_msg)) logger.info(f发送K线数据订阅请求: {subscribe_msg}) async def _send_heartbeat(self) - None: 发送心跳包协议号10010 if not self.ws or self.ws.closed: return heartbeat_msg { code: 10010, trace: self._generate_trace_id() } try: await self.ws.send(json.dumps(heartbeat_msg)) logger.debug(f发送心跳包: {heartbeat_msg}) except Exception as e: logger.error(f发送心跳包失败: {str(e)}) raise def _start_heartbeat_task(self) - None: 启动心跳任务后台定时发送 if self.heartbeat_task and not self.heartbeat_task.done(): self.heartbeat_task.cancel() async def heartbeat_loop(): while self.is_connected and self.ws and not self.ws.closed: try: await self._send_heartbeat() await asyncio.sleep(self.heartbeat_interval) except Exception as e: logger.error(f心跳任务异常: {str(e)}) break self.heartbeat_task asyncio.create_task(heartbeat_loop()) async def _message_listener(self) - None: 监听服务端推送的消息 while self.is_connected and self.ws and not self.ws.closed: try: # 阻塞等待接收消息 message await self.ws.recv() logger.info(f收到服务端消息: {message}) # 解析消息并处理对等Java的OnMessage逻辑 self._handle_received_message(message) except ConnectionClosed: logger.warning(WebSocket连接已关闭停止消息监听) self.is_connected False break except Exception as e: logger.error(f接收/处理消息异常: {str(e)}) def _handle_received_message(self, message: str) - None: 处理接收到的消息按协议号分类 try: msg_data json.loads(message) code msg_data.get(code) trace msg_data.get(trace) data msg_data.get(data, {}) if code 10000: logger.info(f处理成交明细数据 [trace{trace}]: {data}) elif code 10003: logger.info(f处理盘口数据 [trace{trace}]: {data}) elif code 10006: logger.info(f处理K线数据 [trace{trace}]: {data}) elif code 10010: logger.debug(f收到心跳响应 [trace{trace}]) else: logger.warning(f未知协议号消息 [code{code}]: {message}) except json.JSONDecodeError: logger.error(f消息格式错误无法解析JSON: {message}) except Exception as e: logger.error(f处理消息异常: {str(e)}) async def _reconnect_loop(self) - None: 自动重连循环对等Java的startReconnection while True: if not self.is_connected: logger.info(f尝试重连WebSocket间隔{self.reconnect_interval}秒...) try: await self.connect() except Exception: # 重连失败等待后重试 await asyncio.sleep(self.reconnect_interval) else: # 连接正常短暂等待后再次检查 await asyncio.sleep(1) async def start(self) - None: 启动客户端主入口 # 启动自动重连任务 self.reconnect_task asyncio.create_task(self._reconnect_loop()) try: # 首次连接 await self.connect() # 启动消息监听 await self._message_listener() finally: # 清理资源 self.is_connected False if self.heartbeat_task: self.heartbeat_task.cancel() if self.reconnect_task: self.reconnect_task.cancel() if self.ws and not self.ws.closed: await self.ws.close() logger.info(WebSocket客户端已停止) async def main(): 主函数 # 替换为你的实际API Key API_KEY yourApikey client CryptoWebsocketClient(api_keyAPI_KEY) await client.start() if __name__ __main__: try: asyncio.run(main()) except KeyboardInterrupt: logger.info(用户中断退出客户端) except Exception as e: logger.error(f客户端运行异常: {str(e)})更多详细教程请查阅官方文档或者Github。

更多文章