股票价格是随机漫步游走的吗?

2024年2月12日 369点热度 0人点赞 0条评论

股票价格是否是随机的是一个一直处于争论中的话题。我曾经和身边的朋友就这个问题谈过看法,多数倾向于股票价格中有某种规律可循,不是随机的,但我的观点可能稍有不同。我的看法是,就股票价格,即开高收低这四个价格本身的分布而言,特征是随机的,但股票的长期趋势有内生规律可循,而所谓的规律,并不是价格这个简单的因子能够解释的,而是基于一些更宏观的因素,比如经济周期,企业基本面,以及地缘或其他周期性因素的影响。

在交易策略算法的研究中,经常会使用蒙特卡洛式的算法进行大量的数据生成,模拟与回归。就这个问题,我曾经写过一个简单的模拟股票价格K线的工具函数,在这里分享一下。

贴代码之前,首先说明一下这个函数的实现逻辑:

从对股票市场的长期统计数据来看,收益率这个序列符合正态分布。基于此,我们定义一个初始价格,设定一些约束参数,比如需要考虑张跌停板的限制,后续生成符合正态分布的收益率序列以反算对应的K线价格。下面是代码实现:

import numpy as np
import random
from pandas import DataFrame
from datetime import datetime, timedelta

def fake_klines(
    initial_date: datetime,
    initial_close: float,
    num: int,
    precision: int = 2,
    constraint: float = 0.1,
    mean: float = 0,
    std_dev: float = 0.03,
    volume_range: tuple[float, float] = (8000, 10000),
    drop_weekend: bool = True,
) -> DataFrame:
    """
    随机K线生成器

    Args:
    -----
        - initial_date (datetime): 初始日期
        - initial_close (float): 初始收盘价格
        - num (int): 需要生成的K线根数
        - precision (int, optional): 价格精度. Defaults to 2.
        - constraint (float, optional): 涨跌停约束条件. Defaults to 0.1.
        - mean (float, optional): 收益序列均值. Defaults to 0.
        - std_dev (float, optional): 收益率序列标准差. Defaults to 0.03.
        - volume_range (tuple[float, float], optional): 成交量取值范围. Defaults to (8000, 10000).
        - drop_weekend (bool, optional): 日期生成是否不包含周六周日. Defaults to True.

    Returns:
    --------
        DataFrame: K线数据帧
    """

    close = initial_close
    df = DataFrame(columns=["datetime", "open", "high", "low", "close", "volume"])
    i = 0
    bars = 0

    while bars < num:
        today = initial_date + timedelta(days=i)

        if drop_weekend and (today.weekday() == 5 or today.weekday() == 6):
            i += 1
            continue

        random_pcts = np.clip(
            np.random.normal(
                mean, std_dev, 4
            ),
            -1 * constraint,
            constraint
        ).tolist()

        high_pct = max(random_pcts)
        low_pct = min(random_pcts)
        random_pcts.remove(high_pct)
        random_pcts.remove(low_pct)

        df.loc[bars] = [
            today,
            round(close * (1 + random_pcts[0]), precision),
            round(close * (1 + high_pct), precision),
            round(close * (1 + low_pct), precision),
            round(close * (1 + random_pcts[1]), precision),
            random.randint(volume_range[0], volume_range[1]),
        ]
        close = df.loc[bars, "close"]

        i += 1
        bars += 1

    return df

该函数返回一个收益率序列符合均值为mean,标准差为std_dev的K线数据帧。我们以均值为0,标准差为0.03即3%为默认参数,生成5000根K线,其对应的图表如下图所示:

均值为0,标准差为3%,随机5000根K线图表
均值为0,标准差为3%,随机5000根K线的收益率分布直方图

上面的图表看起来是不是和真实的股票走势非常像?如果告诉您这就是一只股票的真实走势,我想多数人并不会怀疑吧,而这的的确确是用随机数生成的假数据。

在fake_klines函数的参数中,mean参数和std_dev参数决定了所生成K线图表的趋势与波动程度,这很好理解,均值mean为正,那么走势一定是长期向上的,为负则为长期下跌趋势;std_dev参数是数据的离散参数,标准差越高,数据的波动就越大。在实际使用这个函数的时候,可以根据需要调整参数设置。下面贴几张上涨趋势和下跌趋势的参数图表:

均值为0.1%,标准差为5%,随机5000根上升趋势的K线图表
均值为0.1%,标准差为5%,随机5000根上升趋势的收益率分布直方图
均值为-0.1%,标准差为5%,随机2000根下跌趋势的K线图表
均值为-0.1%,标准差为5%,随机2000根下跌趋势的收益率分布直方图

上面的图表演示了函数生成的上涨和下跌趋势图表,一个需要说明的是,下跌趋势的图表K线根数是2000根,之所以不生成更多的根数,是因为在长期下跌的趋势中,价格将慢慢趋近于0,而价格越趋近于0,每日涨跌幅的直方分布图上的峰度就会越高,最终趋于失真。

在上面随机生成的K线图表中,我们如果用传统的技术指标工具去分析,可以发现走势出现中枢,前高前低形成的阻力与支撑,技术指标出现顶底背离后价格开始改变运动趋势,几乎你所有的技术指标工具都有用武之地,而这一切的基础,仅仅是随机生成的假数据。

那么问题来了,真实世界的股票价格?到底是不是随机游走的呢?欢迎评论区留下您的观点与看法:)

QThinker

前地产从业者,假装是个程序员,热爱编程与交易 自研QThinker量化交易框架

文章评论