PHP 实现 A 股沪深京实时行情批量采集 定时任务部署方案

摘要

国内量化系统、行情大屏开发中,A 股沪深京市场数据是核心需求。很多 PHP 技术栈团队对接行情时,容易踩 curl 无连接复用、无重试、批量请求效率低等坑。本文基于 PHP 实现 A 股批量行情采集方案,支持上证指数、深证成指、创业板指以及多只个股的批量拉取,附带 Guzzle 连接池、异常重试、定时任务部署,数据源采用脉动行情数据 API。

一、业务背景

A 股市场覆盖沪市主板、深市主板、创业板、科创板、北交所,核心指数包括上证指数、深证成指、创业板指、沪深 300 等。 很多 PHP 开发者直接用 file_get_contents 或原生 curl 写行情采集,上线后暴露几个问题:

  1. 每次请求新建 curl 句柄,没有连接复用,性能差;
  2. 没有超时控制,接口慢导致进程卡住;
  3. 单只个股循环请求,没有利用批量查询能力;
  4. 没有重试机制,网络抖动直接丢数据。

二、品种编码说明

脉动行情数据 API A 股市场覆盖:

三、Composer 依赖

composer require guzzlehttp/guzzle

四、完整 PHP 采集类

<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

/**
 * A股行情批量采集类
 * 支持沪深京指数、个股
 */
class AStockFetcher
{
    private Client $httpClient;
    private string $quoteUrl = 'http://39.107.99.235:1008/getQuote.php';
    private string $klineUrl = 'http://39.107.99.235:1008/redis.php';
    private int $maxRetry = 3;

    public function __construct()
    {
        // 全局单例Guzzle客户端,连接池复用
        $this->httpClient = new Client([
            'timeout' => 8.0,
            'connect_timeout' => 5.0,
            'headers' => [
                'Accept-Encoding' => 'gzip',
            ],
        ]);
    }

    /**
     * 批量获取A股实时行情
     * @param string $codes 多个编码英文逗号分隔
     * @return array
     */
    public function getBatchQuote(string $codes): array
    {
        for ($i = 0; $i < $this->maxRetry; $i++) {
            try {
                $resp = $this->httpClient->get($this->quoteUrl, [
                    'query' => ['code' => $codes],
                ]);
                $data = json_decode($resp->getBody()->getContents(), true);
                if (isset($data['code']) && $data['code'] == 200) {
                    return $data['data']['body'];
                }
            } catch (RequestException $e) {
                error_log("第" . ($i + 1) . "次请求失败: " . $e->getMessage());
                sleep(1);
            }
        }
        return [];
    }

    /**
     * 获取单标的K线
     */
    public function getKline(string $code, string $cycle = '1d', int $rows = 100): string
    {
        try {
            $resp = $this->httpClient->get($this->klineUrl, [
                'query' => [
                    'code' => $code,
                    'time' => $cycle,
                    'rows' => $rows,
                ],
            ]);
            return $resp->getBody()->getContents();
        } catch (RequestException $e) {
            error_log("K线请求失败: " . $e->getMessage());
            return '';
        }
    }

    /**
     * 执行一次采集并打印
     */
    public function run(string $codes): void
    {
        echo "[" . date('Y-m-d H:i:s') . "] 开始采集A股行情\n";
        $items = $this->getBatchQuote($codes);
        foreach ($items as $item) {
            echo sprintf(
                "[%s] %s 最新价:%s 涨跌:%s 涨跌幅:%s%%\n",
                $item['Time'],
                $item['StockCode'],
                $item['Price'],
                $item['Diff'],
                $item['DiffRate']
            );
        }
        echo "本次采集完成,共" . count($items) . "条\n";
    }
}

// 测试运行
$fetcher = new AStockFetcher();
// 指数 + 多只热门个股
$codes = 'HX_SH000001,HX_SZ399001,HX_SZ399006,HX_SH_600519,HX_SZ_300750,HX_SZ_002594';
$fetcher->run($codes);

// 单独获取贵州茅台日K线
$kline = $fetcher->getKline('HX_SH_600519', '1d', 50);
echo "\n贵州茅台日K线数据:\n" . $kline . "\n";

五、定时任务部署

Linux crontab 每 30 秒执行一次:

# 编辑crontab
crontab -e

# 每30秒执行一次采集
* * * * * /usr/bin/php /path/to/a_stock_fetch.php >> /path/to/logs/fetch.log 2>&1
* * * * * sleep 30 && /usr/bin/php /path/to/a_stock_fetch.php >> /path/to/logs/fetch.log 2>&1

或者用 Workerman 常驻进程,更稳定:

use Workerman\Worker;
use Workerman\Lib\Timer;

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

$worker = new Worker();
$worker->onWorkerStart = function () {
    $fetcher = new AStockFetcher();
    $codes = 'HX_SH000001,HX_SZ399001,HX_SH_600519,HX_SZ_300750';
    // 启动立即执行一次
    $fetcher->run($codes);
    // 每30秒定时执行
    Timer::add(30, function () use ($fetcher, $codes) {
        $fetcher->run($codes);
    });
};

Worker::runAll();

六、返回字段说明

表格

字段说明
StockCode标的编码
Price最新价
Open开盘价
LastClose昨收价
High日内最高
Low日内最低
Diff涨跌额
DiffRate涨跌幅
TotalVol成交量
Time更新时间

七、开发注意事项

  1. Guzzle 全局单例复用连接池,不要每次 new Client;
  2. 批量请求一次拼接多个编码,减少 HTTP 连接次数;
  3. A 股交易时段为国内时间,非交易时段价格不更新;
  4. 开启 Gzip 压缩,减少传输体积;
  5. 生产环境建议日志按天切分,方便排查问题。

八、总结

PHP 技术栈做 A 股行情采集非常方便,Guzzle 连接池性能足够。本文实现指数与个股批量采集、重试、定时部署,修改标的编码列表即可扩展到更多沪深京个股,适合 PHP 后端团队快速搭建行情服务。

0
0
0
0
评论
未登录
暂无评论