Logo
Published on

用数据说话 - 港股打新有多赚?

Authors
  • avatar
    Name
    SeanZou
    Twitter

一个疑问

朋友最近迷上了港股打新。

不只是打新,还上了10倍融资。每次申购100港币手续费,融资200万的话,每天利息45元。

我有点担心那种小概率的极端风险——只要遇上一次破发,十倍杠杆下,账户可能直接爆仓。

我想要数据看看:如果长期打新,扣掉申购成本和融资利息,收益到底如何?

开始动手

目标很简单:统计最近一年上市的港股,首日收盘价相对发行价的收益率。

技术选择也简单:Python + 富途API。富途有行情接口,我以为能直接拿到数据。

最初的设想是:

  1. 用API获取最近上市的股票列表
  2. 拿到每只股票的IPO发行价
  3. 获取首日K线数据
  4. 计算收益率

看起来很直接

卡住了

卡在第二步:发行价。

富途API有两个相关接口:

  • get_ipo_list:能拿到发行价,但只返回即将上市的股票
  • get_stock_basicinfo:能拿到上市日期,但没有发行价

我需要的是历史数据:已经上市的股票,但这两个接口,一个只给未来,一个不给价格。

卡住了。

转折

既然API没有,能不能让AI去查?

这个想法有点荒谬,但值得试试。

方案是这样的:

  1. get_stock_basicinfo获取已上市的股票和上市日期
  2. 用通义千问模型,开启联网搜索,让它去查每只股票的IPO发行价
  3. 并发请求,10个并发
  4. 加上重试机制,最多重试3次

代码实现在ipo_fetcher.py里:

def get_ipo_price_from_ai(stock_code: str, stock_name: str, max_retries: int = 3) -> float:
    """通过 qwen3-max 模型获取股票的 IPO 发行价"""
    client = OpenAI(
        api_key=os.getenv("QWEN_API_KEY"),
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    )
    
    for attempt in range(1, max_retries + 1):
        try:
            completion = client.chat.completions.create(
                model="qwen3-max",
                messages=[
                    {"role": "user", "content": f"{stock_code} {stock_name} 港股 IPO 发行价格,直接返回数字,无需单位"},
                ],
                extra_body={"enable_search": True}
            )
            
            content = completion.choices[0].message.content.strip()
            
            # 检查返回是否为纯数字
            if re.match(r'^\d+\.?\d*$', content):
                price = float(content)
                return price
            
            # 尝试提取数字
            match = re.search(r'(\d+\.?\d*)', content)
            if match:
                price = float(match.group(1))
                if attempt < max_retries:
                    continue  # 重试以获取更好的结果
                return price
                
        except Exception as e:
            if attempt < max_retries:
                continue
    
    return 0.0  # 失败返回0

并发获取的逻辑:

def fetch_ipo_prices_concurrent(stock_list: pd.DataFrame, max_workers: int = 10) -> pd.DataFrame:
    """并发获取股票的 IPO 发行价"""
    result = stock_list.copy()
    result['ipo_price'] = 0.0
    
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        future_to_idx = {
            executor.submit(get_ipo_price_from_ai, row['code'], row['name']): idx
            for idx, row in result.iterrows()
        }
        
        for future in as_completed(future_to_idx):
            idx = future_to_idx[future]
            price = future.result()
            result.at[idx, 'ipo_price'] = price
    
    # 过滤掉价格为0的股票
    result = result[result['ipo_price'] > 0].copy()
    return result

这个方案有点野,但它工作了。

数据出来了

程序跑完,拿到了110只股票的数据。

部分结果:

股票代码名称上市日期发行价首日收盘价收益率
HK.02655GUOXIA TECH2025-12-1620.143.8117.91%
HK.02659BAO PHARMA-B2025-12-1026.3863.0138.82%
HK.02687ABLE DIGITAL2025-12-0867.5126.487.26%
HK.02658TIANYU SEMI2025-12-0558.040.5-30.17%
HK.02408XIAO NOODLES2025-12-057.045.08-27.84%
HK.02718MININGLAMP-W2025-11-03141.0290.6106.1%
HK.01384DEEPEXI TECH2025-10-2826.6666.8150.56%
HK.02650ZHIDA TECH2025-10-1066.92195.5192.14%
HK.02560CONCH MAT TECH2025-01-093.01.39-53.81%

统计结果:

  • 样本数:110只
  • 平均收益率:40.85%
  • 中位数:20.34%
  • 最高收益:330.0%(GOLDEN LEAF INT)
  • 最低收益:-53.81%(CONCH MAT TECH)
  • 正收益:76只(69.1%)
  • 负收益:34只(30.9%)

数据不会给答案

40.85%的平均收益率,看起来不错。

但这个数字,不能直接回答“打新划不划算”。

它没有告诉你:

  • 中签概率是多少
  • 申购100次,能中几次
  • 每次融资的利息成本
  • 破发时的心理压力
  • 极端亏损的承受能力

数据它呈现事实,但不替人选择。

有些决定,数据帮不了忙。风险和收益的权衡,最终还是个人选择。


项目代码:https://github.com/wersling/futu_analysis