印度股票数据 PHP 对接文档 覆盖 BSE(孟买证券交易所)和 NSE(印度国家证券交易所)的实时数据

本文档详细介绍如何使用 PHP 语言对接 StockTV 印度股票数据源,覆盖 BSE(孟买证券交易所)和 NSE(印度国家证券交易所)的实时数据。

🚀 快速开始

环境要求

  • PHP 7.4+
  • cURL 扩展
  • JSON 扩展
  • 网络连接(可访问 api.stocktv.top

🏗️ 核心架构

项目结构

复制代码
src/
├── config/
│   └── StockTVConfig.php
├── models/
│   ├── Stock.php
│   ├── Index.php
│   ├── KLine.php
│   └── ApiResponse.php
├── clients/
│   ├── StockTVHttpClient.php
│   └── StockTVWebSocketClient.php
├── services/
│   └── IndiaStockService.php
└── examples/
    └── IndiaStockDemo.php

📦 核心代码实现

1. 配置类

php 复制代码
<?php
// src/config/StockTVConfig.php

namespace StockTV\Config;

/**
 * StockTV API 配置类
 */
class StockTVConfig
{
    // API 基础配置
    const BASE_URL = 'https://api.stocktv.top';
    const WS_URL = 'wss://ws-api.stocktv.top/connect';
    
    // 印度市场配置
    const INDIA_COUNTRY_ID = 14;
    const NSE_EXCHANGE_ID = 46;
    const BSE_EXCHANGE_ID = 74;
    
    // API 接口路径
    const STOCK_LIST = '/stock/stocks';
    const QUERY_STOCKS = '/stock/queryStocks';
    const STOCKS_BY_PIDS = '/stock/stocksByPids';
    const INDICES = '/stock/indices';
    const INDICES_BY_ID = '/stock/indicesById';
    const KLINE = '/stock/kline';
    const UPDOWN_LIST = '/stock/updownList';
    const GET_IPO = '/stock/getIpo';
    const COMPANIES = '/stock/companies';
    const COMPANY_URL = '/stock/companyUrl';
    const NEWS = '/stock/news';
    
    private $apiKey;
    private $timeout = 30;
    
    public function __construct(string $apiKey)
    {
        $this->apiKey = $apiKey;
    }
    
    public function getApiKey(): string
    {
        return $this->apiKey;
    }
    
    public function getTimeout(): int
    {
        return $this->timeout;
    }
    
    public function setTimeout(int $timeout): self
    {
        $this->timeout = $timeout;
        return $this;
    }
}

2. 数据模型类

股票数据模型
php 复制代码
<?php
// src/models/Stock.php

namespace StockTV\Models;

/**
 * 印度股票数据模型
 */
class Stock
{
    public $id;
    public $symbol;
    public $name;
    public $last;
    public $chg;
    public $chgPct;
    public $high;
    public $low;
    public $volume;
    public $open;
    public $exchangeId;
    public $countryId;
    public $countryNameTranslated;
    public $flag;
    public $fundamentalMarketCap;
    public $fundamentalRevenue;
    public $technicalDay;
    public $technicalHour;
    public $technicalWeek;
    public $technicalMonth;
    public $performanceDay;
    public $performanceWeek;
    public $performanceMonth;
    public $performanceYtd;
    public $time;
    public $url;
    
    public function __construct(array $data = [])
    {
        foreach ($data as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
    }
    
    public function getExchangeName(): string
    {
        if ($this->exchangeId == \StockTV\Config\StockTVConfig::NSE_EXCHANGE_ID) {
            return 'NSE';
        } elseif ($this->exchangeId == \StockTV\Config\StockTVConfig::BSE_EXCHANGE_ID) {
            return 'BSE';
        }
        return 'Unknown';
    }
    
    public function isGaining(): bool
    {
        return $this->chgPct > 0;
    }
    
    public function getFormattedChange(): string
    {
        $sign = $this->chgPct > 0 ? '+' : '';
        return $sign . number_format($this->chgPct, 2) . '%';
    }
    
    public function getFormattedPrice(): string
    {
        return '₹' . number_format($this->last, 2);
    }
}
指数数据模型
php 复制代码
<?php
// src/models/Index.php

namespace StockTV\Models;

/**
 * 指数数据模型
 */
class Index
{
    public $id;
    public $name;
    public $symbol;
    public $last;
    public $chg;
    public $chgPct;
    public $high;
    public $low;
    public $isOpen;
    public $flag;
    public $url;
    public $time;
    
    public function __construct(array $data = [])
    {
        foreach ($data as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
    }
    
    public function isGaining(): bool
    {
        return $this->chgPct > 0;
    }
    
    public function getFormattedChange(): string
    {
        $sign = $this->chgPct > 0 ? '+' : '';
        return $sign . number_format($this->chgPct, 2) . '%';
    }
}
K线数据模型
php 复制代码
<?php
// src/models/KLine.php

namespace StockTV\Models;

/**
 * K线数据模型
 */
class KLine
{
    public $time;
    public $open;
    public $high;
    public $low;
    public $close;
    public $volume;
    public $vo;
    
    public function __construct(array $data = [])
    {
        foreach ($data as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
    }
    
    public function getAmplitude(): float
    {
        if ($this->open == 0) {
            return 0;
        }
        return (($this->high - $this->low) / $this->open) * 100;
    }
    
    public function getChangePercent(): float
    {
        if ($this->open == 0) {
            return 0;
        }
        return (($this->close - $this->open) / $this->open) * 100;
    }
}
API响应包装类
php 复制代码
<?php
// src/models/ApiResponse.php

namespace StockTV\Models;

/**
 * API通用响应包装类
 */
class ApiResponse
{
    public $code;
    public $message;
    public $data;
    
    public function __construct(array $data = [])
    {
        foreach ($data as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
    }
    
    public function isSuccess(): bool
    {
        return $this->code === 200;
    }
}

/**
 * 股票列表响应包装类
 */
class StockListResponse
{
    public $records;
    public $total;
    public $size;
    public $current;
    public $pages;
    
    public function __construct(array $data = [])
    {
        foreach ($data as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
        
        // 转换records为Stock对象数组
        if (isset($data['records']) && is_array($data['records'])) {
            $this->records = array_map(function($item) {
                return new Stock($item);
            }, $data['records']);
        }
    }
}

3. HTTP客户端实现

php 复制代码
<?php
// src/clients/StockTVHttpClient.php

namespace StockTV\Clients;

use StockTV\Config\StockTVConfig;
use StockTV\Models\ApiResponse;
use StockTV\Models\Stock;
use StockTV\Models\Index;
use StockTV\Models\KLine;
use StockTV\Models\StockListResponse;

/**
 * StockTV HTTP API客户端
 */
class StockTVHttpClient
{
    private $config;
    private $lastResponse;
    
    public function __construct(StockTVConfig $config)
    {
        $this->config = $config;
    }
    
    /**
     * 获取印度股票列表
     */
    public function getIndiaStocks(int $pageSize = 50, int $page = 1): array
    {
        $params = [
            'countryId' => StockTVConfig::INDIA_COUNTRY_ID,
            'pageSize' => $pageSize,
            'page' => $page,
            'key' => $this->config->getApiKey()
        ];
        
        $response = $this->makeRequest(StockTVConfig::STOCK_LIST, $params);
        
        if ($response->isSuccess()) {
            $stockListResponse = new StockListResponse($response->data);
            return $stockListResponse->records;
        }
        
        throw new \Exception("获取印度股票列表失败: " . $response->message);
    }
    
    /**
     * 查询单个股票
     */
    public function queryStock(?int $id = null, ?string $symbol = null, ?string $name = null): array
    {
        $params = ['key' => $this->config->getApiKey()];
        
        if ($id !== null) {
            $params['id'] = $id;
        }
        if ($symbol !== null) {
            $params['symbol'] = $symbol;
        }
        if ($name !== null) {
            $params['name'] = $name;
        }
        
        $response = $this->makeRequest(StockTVConfig::QUERY_STOCKS, $params);
        
        if ($response->isSuccess()) {
            return array_map(function($item) {
                return new Stock($item);
            }, $response->data);
        }
        
        throw new \Exception("查询股票失败: " . $response->message);
    }
    
    /**
     * 批量查询多个股票
     */
    public function getStocksByPids(array $pids): array
    {
        if (empty($pids)) {
            throw new \InvalidArgumentException("股票PID列表不能为空");
        }
        
        $params = [
            'key' => $this->config->getApiKey(),
            'pids' => implode(',', $pids)
        ];
        
        $response = $this->makeRequest(StockTVConfig::STOCKS_BY_PIDS, $params);
        
        if ($response->isSuccess()) {
            return array_map(function($item) {
                return new Stock($item);
            }, $response->data);
        }
        
        throw new \Exception("批量查询股票失败: " . $response->message);
    }
    
    /**
     * 获取印度主要指数
     */
    public function getIndiaIndices(): array
    {
        $params = [
            'countryId' => StockTVConfig::INDIA_COUNTRY_ID,
            'key' => $this->config->getApiKey()
        ];
        
        $response = $this->makeRequest(StockTVConfig::INDICES, $params);
        
        if ($response->isSuccess()) {
            return array_map(function($item) {
                return new Index($item);
            }, $response->data);
        }
        
        throw new \Exception("获取印度指数失败: " . $response->message);
    }
    
    /**
     * 通过ID查询特定指数
     */
    public function getIndexById(int $id): array
    {
        $params = [
            'id' => $id,
            'key' => $this->config->getApiKey()
        ];
        
        $response = $this->makeRequest(StockTVConfig::INDICES_BY_ID, $params);
        
        if ($response->isSuccess()) {
            return array_map(function($item) {
                return new Index($item);
            }, $response->data);
        }
        
        throw new \Exception("获取指数失败: " . $response->message);
    }
    
    /**
     * 获取K线数据
     */
    public function getKLineData(int $pid, string $interval): array
    {
        $params = [
            'pid' => $pid,
            'interval' => $interval,
            'key' => $this->config->getApiKey()
        ];
        
        $response = $this->makeRequest(StockTVConfig::KLINE, $params);
        
        if ($response->isSuccess()) {
            return array_map(function($item) {
                return new KLine($item);
            }, $response->data);
        }
        
        throw new \Exception("获取K线数据失败: " . $response->message);
    }
    
    /**
     * 获取涨跌排行榜
     */
    public function getUpDownList(int $type): array
    {
        $params = [
            'countryId' => StockTVConfig::INDIA_COUNTRY_ID,
            'type' => $type,
            'key' => $this->config->getApiKey()
        ];
        
        $response = $this->makeRequest(StockTVConfig::UPDOWN_LIST, $params);
        
        if ($response->isSuccess()) {
            return array_map(function($item) {
                return new Stock($item);
            }, $response->data);
        }
        
        throw new \Exception("获取排行榜失败: " . $response->message);
    }
    
    /**
     * 获取IPO数据
     */
    public function getIpoList(?int $type = null): array
    {
        $params = [
            'countryId' => StockTVConfig::INDIA_COUNTRY_ID,
            'key' => $this->config->getApiKey()
        ];
        
        if ($type !== null) {
            $params['type'] = $type;
        }
        
        $response = $this->makeRequest(StockTVConfig::GET_IPO, $params);
        
        if ($response->isSuccess()) {
            return $response->data;
        }
        
        throw new \Exception("获取IPO数据失败: " . $response->message);
    }
    
    /**
     * 通用HTTP请求方法
     */
    private function makeRequest(string $endpoint, array $params = []): ApiResponse
    {
        $url = StockTVConfig::BASE_URL . $endpoint . '?' . http_build_query($params);
        
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => $this->config->getTimeout(),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'User-Agent: StockTV-PHP-Client/1.0'
            ]
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($error) {
            throw new \Exception("HTTP请求失败: " . $error);
        }
        
        if ($httpCode !== 200) {
            throw new \Exception("HTTP请求失败,状态码: " . $httpCode);
        }
        
        $data = json_decode($response, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new \Exception("JSON解析失败: " . json_last_error_msg());
        }
        
        $this->lastResponse = $data;
        return new ApiResponse($data);
    }
    
    /**
     * 获取最后一次响应数据
     */
    public function getLastResponse(): ?array
    {
        return $this->lastResponse;
    }
}

4. WebSocket客户端实现

php 复制代码
<?php
// src/clients/StockTVWebSocketClient.php

namespace StockTV\Clients;

use StockTV\Config\StockTVConfig;
use Ratchet\Client\WebSocket;
use Ratchet\Client\Connector;
use React\EventLoop\Factory;
use React\Socket\Connector as ReactConnector;

/**
 * StockTV WebSocket实时数据客户端
 */
class StockTVWebSocketClient
{
    private $config;
    private $loop;
    private $connector;
    private $webSocket;
    private $callbacks;
    
    public function __construct(StockTVConfig $config)
    {
        $this->config = $config;
        $this->loop = Factory::create();
        $this->connector = new Connector($this->loop);
        $this->callbacks = [
            'message' => [],
            'error' => [],
            'close' => []
        ];
    }
    
    /**
     * 连接WebSocket服务器
     */
    public function connect(): void
    {
        $wsUrl = StockTVConfig::WS_URL . '?key=' . $this->config->getApiKey();
        
        $this->connector->__invoke($wsUrl)
            ->then(function(WebSocket $conn) {
                $this->webSocket = $conn;
                $this->onOpen($conn);
                
                $conn->on('message', function($msg) use ($conn) {
                    $this->onMessage($conn, $msg);
                });
                
                $conn->on('close', function($code = null, $reason = null) use ($conn) {
                    $this->onClose($conn, $code, $reason);
                });
                
            }, function(\Exception $e) {
                $this->onError($e);
            });
    }
    
    /**
     * 启动事件循环
     */
    public function run(): void
    {
        $this->loop->run();
    }
    
    /**
     * 停止事件循环
     */
    public function stop(): void
    {
        if ($this->loop) {
            $this->loop->stop();
        }
    }
    
    /**
     * 连接建立回调
     */
    private function onOpen(WebSocket $conn): void
    {
        echo "WebSocket连接已建立\n";
    }
    
    /**
     * 消息接收回调
     */
    private function onMessage(WebSocket $conn, $msg): void
    {
        $data = json_decode($msg, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            echo "JSON解析失败: " . json_last_error_msg() . "\n";
            return;
        }
        
        $this->handleRealTimeData($data);
        
        // 执行用户定义的回调
        foreach ($this->callbacks['message'] as $callback) {
            call_user_func($callback, $data);
        }
    }
    
    /**
     * 连接关闭回调
     */
    private function onClose(WebSocket $conn, $code, $reason): void
    {
        echo "WebSocket连接已关闭: code={$code}, reason={$reason}\n";
        
        foreach ($this->callbacks['close'] as $callback) {
            call_user_func($callback, $code, $reason);
        }
    }
    
    /**
     * 错误回调
     */
    private function onError(\Exception $e): void
    {
        echo "WebSocket连接错误: " . $e->getMessage() . "\n";
        
        foreach ($this->callbacks['error'] as $callback) {
            call_user_func($callback, $e);
        }
    }
    
    /**
     * 处理实时数据
     */
    private function handleRealTimeData(array $data): void
    {
        if (isset($data['pid'])) {
            $symbol = $data['symbol'] ?? $data['pid'];
            $price = $data['last_numeric'] ?? 'N/A';
            $changePercent = $data['pcp'] ?? '0';
            
            echo "实时行情: {$symbol} - 价格: {$price}, 涨跌幅: {$changePercent}%\n";
            
            // 价格预警逻辑
            $changePercentNum = floatval($changePercent);
            if (abs($changePercentNum) > 2.0) {
                echo "🚨 价格波动预警: {$symbol} 波动 {$changePercentNum}%\n";
            }
        }
    }
    
    /**
     * 添加消息回调
     */
    public function onMessageCallback(callable $callback): self
    {
        $this->callbacks['message'][] = $callback;
        return $this;
    }
    
    /**
     * 添加错误回调
     */
    public function onErrorCallback(callable $callback): self
    {
        $this->callbacks['error'][] = $callback;
        return $this;
    }
    
    /**
     * 添加关闭回调
     */
    public function onCloseCallback(callable $callback): self
    {
        $this->callbacks['close'][] = $callback;
        return $this;
    }
    
    /**
     * 发送消息
     */
    public function send(string $message): void
    {
        if ($this->webSocket) {
            $this->webSocket->send($message);
        }
    }
    
    /**
     * 关闭连接
     */
    public function close(): void
    {
        if ($this->webSocket) {
            $this->webSocket->close();
        }
        $this->stop();
    }
}

5. 服务层封装

php 复制代码
<?php
// src/services/IndiaStockService.php

namespace StockTV\Services;

use StockTV\Config\StockTVConfig;
use StockTV\Clients\StockTVHttpClient;
use StockTV\Clients\StockTVWebSocketClient;
use StockTV\Models\Stock;
use StockTV\Models\Index;
use StockTV\Models\KLine;

/**
 * 印度股票数据服务
 */
class IndiaStockService
{
    private $httpClient;
    private $wsClient;
    
    public function __construct(string $apiKey)
    {
        $config = new StockTVConfig($apiKey);
        $this->httpClient = new StockTVHttpClient($config);
        $this->wsClient = new StockTVWebSocketClient($config);
    }
    
    /**
     * 获取Nifty 50成分股
     */
    public function getNifty50Stocks(): array
    {
        try {
            $stocks = $this->httpClient->getIndiaStocks(50, 1);
            echo "成功获取 " . count($stocks) . " 只印度股票\n";
            return $stocks;
        } catch (\Exception $e) {
            echo "获取Nifty 50成分股失败: " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    /**
     * 获取印度主要指数
     */
    public function getMajorIndices(): array
    {
        try {
            $indices = $this->httpClient->getIndiaIndices();
            echo "成功获取 " . count($indices) . " 个印度指数\n";
            return $indices;
        } catch (\Exception $e) {
            echo "获取印度指数失败: " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    /**
     * 查询特定股票
     */
    public function getStockBySymbol(string $symbol): ?Stock
    {
        try {
            $stocks = $this->httpClient->queryStock(null, $symbol, null);
            if (empty($stocks)) {
                echo "未找到股票: {$symbol}\n";
                return null;
            }
            echo "查询股票 {$symbol} 成功\n";
            return $stocks[0];
        } catch (\Exception $e) {
            echo "查询股票失败: {$symbol} - " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    /**
     * 批量查询股票
     */
    public function getStocksBySymbols(array $symbols): array
    {
        $results = [];
        foreach ($symbols as $symbol) {
            try {
                $stock = $this->getStockBySymbol($symbol);
                if ($stock) {
                    $results[] = $stock;
                }
            } catch (\Exception $e) {
                // 单个股票查询失败,继续处理其他股票
                continue;
            }
        }
        echo "批量查询成功,获取 " . count($results) . " 只股票\n";
        return $results;
    }
    
    /**
     * 获取股票K线数据
     */
    public function getStockKLine(int $pid, string $interval): array
    {
        try {
            $klines = $this->httpClient->getKLineData($pid, $interval);
            echo "成功获取股票 {$pid} 的K线数据,共 " . count($klines) . " 条\n";
            return $klines;
        } catch (\Exception $e) {
            echo "获取K线数据失败: pid={$pid} - " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    /**
     * 获取涨幅榜
     */
    public function getGainers(): array
    {
        try {
            $gainers = $this->httpClient->getUpDownList(1);
            echo "成功获取涨幅榜,共 " . count($gainers) . " 只股票\n";
            return $gainers;
        } catch (\Exception $e) {
            echo "获取涨幅榜失败: " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    /**
     * 获取跌幅榜
     */
    public function getLosers(): array
    {
        try {
            $losers = $this->httpClient->getUpDownList(2);
            echo "成功获取跌幅榜,共 " . count($losers) . " 只股票\n";
            return $losers;
        } catch (\Exception $e) {
            echo "获取跌幅榜失败: " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    /**
     * 获取IPO数据
     */
    public function getUpcomingIPOs(): array
    {
        try {
            $ipos = $this->httpClient->getIpoList(1); // 1表示未上市
            echo "成功获取IPO数据,共 " . count($ipos) . " 个\n";
            return $ipos;
        } catch (\Exception $e) {
            echo "获取IPO数据失败: " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    /**
     * 启动实时数据监控
     */
    public function startRealTimeMonitoring(): void
    {
        try {
            // 添加消息处理回调
            $this->wsClient->onMessageCallback(function($data) {
                $this->handleRealTimeData($data);
            });
            
            $this->wsClient->connect();
            echo "实时数据监控已启动\n";
            
            // 启动事件循环
            $this->wsClient->run();
            
        } catch (\Exception $e) {
            echo "启动实时数据监控失败: " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    /**
     * 处理实时数据
     */
    private function handleRealTimeData(array $data): void
    {
        if (isset($data['pid'])) {
            $symbol = $data['symbol'] ?? $data['pid'];
            $price = $data['last_numeric'] ?? 'N/A';
            $changePercent = $data['pcp'] ?? '0';
            
            $trend = floatval($changePercent) >= 0 ? '📈' : '📉';
            echo "{$trend} 实时行情: {$symbol} - 价格: ₹{$price}, 涨跌幅: {$changePercent}%\n";
            
            // 价格预警逻辑
            $changePercentNum = floatval($changePercent);
            if (abs($changePercentNum) > 5.0) {
                echo "🚨 大幅波动预警: {$symbol} 波动 {$changePercentNum}%\n";
            }
        }
    }
    
    /**
     * 停止实时数据监控
     */
    public function stopRealTimeMonitoring(): void
    {
        $this->wsClient->close();
        echo "实时数据监控已停止\n";
    }
}

6. 使用示例

php 复制代码
<?php
// examples/IndiaStockDemo.php

require_once __DIR__ . '/../vendor/autoload.php';

use StockTV\Services\IndiaStockService;
use StockTV\Models\Stock;
use StockTV\Models\Index;

/**
 * 印度股票数据使用示例
 */
class IndiaStockDemo
{
    private $stockService;
    
    public function __construct(string $apiKey)
    {
        $this->stockService = new IndiaStockService($apiKey);
    }
    
    public function runDemo(): void
    {
        echo "=== StockTV 印度股票数据演示程序开始 ===\n\n";
        
        try {
            // 1. 获取印度主要指数
            $this->demonstrateIndices();
            
            // 2. 查询特定股票
            $this->demonstrateStockQuery();
            
            // 3. 获取Nifty 50成分股示例
            $this->demonstrateNifty50();
            
            // 4. 获取K线数据
            $this->demonstrateKLineData();
            
            // 5. 获取排行榜
            $this->demonstrateRankings();
            
            echo "\n=== 演示程序执行完成 ===\n";
            
        } catch (Exception $e) {
            echo "演示程序执行失败: " . $e->getMessage() . "\n";
        }
    }
    
    /**
     * 演示指数数据获取
     */
    private function demonstrateIndices(): void
    {
        echo "1. 印度主要指数\n";
        echo str_repeat("-", 50) . "\n";
        
        $indices = $this->stockService->getMajorIndices();
        
        foreach ($indices as $index) {
            $trend = $index->isGaining() ? '📈' : '📉';
            $changeSign = $index->isGaining() ? '+' : '';
            
            echo "{$trend} {$index->name}: {$index->last} ";
            echo "({$changeSign}{$index->chgPct}%)\n";
        }
        echo "\n";
    }
    
    /**
     * 演示股票查询
     */
    private function demonstrateStockQuery(): void
    {
        echo "2. 查询特定股票\n";
        echo str_repeat("-", 50) . "\n";
        
        // 查询Reliance Industries
        $reliance = $this->stockService->getStockBySymbol('RELIANCE');
        $this->printStockInfo($reliance, 'Reliance Industries');
        
        // 查询TCS
        $tcs = $this->stockService->getStockBySymbol('TCS');
        $this->printStockInfo($tcs, 'Tata Consultancy Services');
        
        echo "\n";
    }
    
    /**
     * 演示Nifty 50成分股
     */
    private function demonstrateNifty50(): void
    {
        echo "3. Nifty 50成分股(示例)\n";
        echo str_repeat("-", 50) . "\n";
        
        $niftyStocks = $this->stockService->getNifty50Stocks();
        
        // 显示前10只股票
        $count = 0;
        foreach ($niftyStocks as $stock) {
            if ($count >= 10) break;
            
            $trend = $stock->isGaining() ? '🟢' : '🔴';
            $changeSign = $stock->isGaining() ? '+' : '';
            
            echo "{$trend} {$stock->symbol}: ₹{$stock->last} ";
            echo "({$changeSign}{$stock->chgPct}%) - {$stock->name}\n";
            
            $count++;
        }
        echo "\n";
    }
    
    /**
     * 演示K线数据获取
     */
    private function demonstrateKLineData(): void
    {
        echo "4. K线数据示例\n";
        echo str_repeat("-", 50) . "\n";
        
        $reliance = $this->stockService->getStockBySymbol('RELIANCE');
        if ($reliance) {
            $klines = $this->stockService->getStockKLine($reliance->id, 'P1D');
            
            echo "Reliance Industries 近期日K线数据:\n";
            $count = 0;
            foreach ($klines as $kline) {
                if ($count >= 5) break;
                
                $date = date('Y-m-d H:i:s', $kline->time / 1000);
                $amplitude = number_format($kline->getAmplitude(), 2);
                
                echo "时间: {$date}, 开: ₹{$kline->open}, ";
                echo "高: ₹{$kline->high}, 低: ₹{$kline->low}, ";
                echo "收: ₹{$kline->close}, 振幅: {$amplitude}%\n";
                
                $count++;
            }
        }
        echo "\n";
    }
    
    /**
     * 演示排行榜功能
     */
    private function demonstrateRankings(): void
    {
        echo "5. 市场排行榜\n";
        echo str_repeat("-", 50) . "\n";
        
        // 获取涨幅榜
        $gainers = $this->stockService->getGainers();
        echo "📈 今日涨幅榜(前5):\n";
        $count = 0;
        foreach ($gainers as $stock) {
            if ($count >= 5) break;
            
            $changeSign = $stock->isGaining() ? '+' : '';
            echo "   {$stock->symbol}: ₹{$stock->last} ";
            echo "({$changeSign}{$stock->chgPct}%) - {$stock->name}\n";
            
            $count++;
        }
        
        echo "\n";
        
        // 获取跌幅榜
        $losers = $this->stockService->getLosers();
        echo "📉 今日跌幅榜(前5):\n";
        $count = 0;
        foreach ($losers as $stock) {
            if ($count >= 5) break;
            
            echo "   {$stock->symbol}: ₹{$stock->last} ";
            echo "({$stock->chgPct}%) - {$stock->name}\n";
            
            $count++;
        }
        echo "\n";
    }
    
    /**
     * 打印股票信息
     */
    private function printStockInfo(?Stock $stock, string $description): void
    {
        if ($stock) {
            $status = $stock->open ? '🟢 交易中' : '🔴 已收盘';
            $trend = $stock->isGaining() ? '📈' : '📉';
            
            echo "{$trend} {$description} - {$status}\n";
            echo "   代码: {$stock->symbol} | 价格: ₹{$stock->last}\n";
            echo "   涨跌: ₹{$stock->chg} ({$stock->getFormattedChange()})\n";
            echo "   最高: ₹{$stock->high} | 最低: ₹{$stock->low} | 成交量: {$stock->volume}\n";
            
            if ($stock->technicalDay) {
                $techName = $this->getTechnicalIndicatorName($stock->technicalDay);
                echo "   技术指标: {$techName}\n";
            }
        }
        echo "\n";
    }
    
    /**
     * 获取技术指标中文名称
     */
    private function getTechnicalIndicatorName(string $indicator): string
    {
        $map = [
            'strong_buy' => '强烈买入',
            'buy' => '买入',
            'neutral' => '中性',
            'sell' => '卖出',
            'strong_sell' => '强烈卖出'
        ];
        
        return $map[$indicator] ?? $indicator;
    }
}

// 运行演示程序
$apiKey = '您的API_KEY'; // 替换为实际的API Key

$demo = new IndiaStockDemo($apiKey);
$demo->runDemo();

🎯 高级功能

实时价格监控器

php 复制代码
<?php
// examples/PriceMonitor.php

require_once __DIR__ . '/../vendor/
相关推荐
lkbhua莱克瓦241 小时前
集合进阶6——TreeMap底层原理
java·开发语言·笔记·学习方法·hashmap
普通网友1 小时前
内存对齐与缓存友好设计
开发语言·c++·算法
lsx2024061 小时前
DOM 节点信息
开发语言
普通网友2 小时前
C++编译期数据结构
开发语言·c++·算法
HalvmånEver2 小时前
Linux:基础开发工具(六)
linux·运维·服务器
安卓蓝牙Vincent2 小时前
Android多SDK合并为单个JAR包的完整指南
android
whatever who cares2 小时前
Java/Android中BigDecimal的相关操作
android·java·开发语言
普通网友2 小时前
嵌入式C++安全编码
开发语言·c++·算法
烤麻辣烫2 小时前
黑马程序员苍穹外卖(新手) DAY3
java·开发语言·spring boot·学习·intellij-idea