写点什么

股票价格在随机漫步吗?用 Python 来告诉你

2019 年 6 月 13 日

股票价格在随机漫步吗?用Python来告诉你

1. 什么是随机漫步

在这个世界上存在的现象大体分为必然现象和随机现象两类。必然现象就像太阳每天必然从东边升起,西边落下那样,在相同条件下完全可以事先预测到它的结果。随机现象则不同,它在个别试验中会呈现不确定的结果,比如抛掷一次硬币,可能是正面,也可能是反面,不过在相同的条件下大量重复试验中又会呈现一定的规律性,因为当抛掷的次数逐渐增多时,出现正面或者反面的频率会逐渐接近 50%。


很显然,股票的涨跌属于随机现象,因为没有人能确定明天的具体走势。人们普遍对于不确定性存在恐惧,于是用一个介于 0 与 1 之间的数值来表示各个随机现象发生的可能性,这个数值就是概率。概率可以辅助人们对于未知结果作出理性的判断,量化交易的精髓正是如此,它从历史数据中得到大概率下获利的交易策略。


股市波动的规律一直是一个极具挑战性的世界级难题,迄今为止已经出现过多个具有代表性的理论,随机漫步理论(Random Walk Theory)就是其中之一。随机漫步理论描述的正是股票涨跌的概率。早在 1990 年,巴黎一位博士生路易斯·巴舍利耶(1887—1946)跟踪当时巴黎股市起伏,期望用数学工具来描述股价变动过程。在他的论文《投机理论》中指出,股票价格的日常变动从根本上说是不可预知的,类似于“布朗运动”那样属于随机游走,没有任何规律可循。就好比一个人购买一只股票后立即将其卖掉,那么他输赢的概率是相等的。


理论中对于随机漫步现象解释到:由于流入市场的股票信息是公开的,市场中成千上万的专业人士会对股票进行详细的分析,驱动着股票多空交易,因此股票当前的价格实际已经反映了供求关系和内在的价值,而这个价格正是专业人士经过分析后所构成的一个合理价位,后续的市价会围绕着它上下波动。引起波动的原因会是新的经济、政治新闻、收购、合并、加息减息等等,这些消息是没有任何轨迹可循地流入市场,使得专业人士重新分析股票的价值,给出买卖方针,致使股票发生新的变化。由此可见,股票现时是没有记忆系统的,过去、现在和未来的涨跌并无关联,企图用股价的波动找出一个原理去预知股市去向是行不通的。随机漫步理论对技术图表派无疑是一个正面大敌,虽然理论至今仍然在经受着时间的检验,但如果理论一旦成立,所有股票专家都无立足之地。


不少专家学者都对随机漫步的论调有过研究,在《漫步华尔街》一书中提到了一个例子,作者让他的学生用抛硬币的方式构建一个假想的股价走势图。股价开始时定为 50 美元,此后每个交易日的收盘价右抛硬币的结果来确定:若抛出正面朝上便假定股票当天收盘价较前一天上涨 0.5%,反之则下跌 0.5%。最后根据随机抛硬币画出的走势图居然和正常的股价走势图非常相似,有“头肩顶”形态,甚至还呈现周期性的变动。


事实上股票价格真的就无法预测了吗?人生苦短,我们不妨用 Python 来探究下其中的奥秘。


2. Python 随机数的生成

Python 内置的 random 模块和第三方库 NumPy 的 random 模块都提供了生成随机漫步序列的方法,分别为 random.randint()和 numpy.random.randint()函数。NumPy 中主要以 N 维数组对象 ndarray 存储数据的,ndarray 作为 NumPy 的核心,不仅具有矢量算术运算的能力,并且在处理多维的大规模数组时快速且节省空间。


我们先了解下 ndarray 在效率方面的优势,通过对比 numpy.random.randint()方法生成 1000000 个规模的随机数组和 random.randint() 方法生成一个等价的 Python 列表,以此来了解下它们之间具体的性能差距。实现代码如下所示:


def list_test():    walk = []    for _ in range(1000000):        walk.append(random.randint(0, 1))
def ndarray_test(): np.random.randint(0, 2, size=1000000)
t1 = timeit('list_test()', 'from __main__ import list_test', number=1)t2 = timeit('ndarray_test()', 'from __main__ import ndarray_test', number=1)
print("list:{}".format(t1)) # list:1.3908312620000003print("ndarray:{}".format(t2)) # ndarray:0.009495778999999871
复制代码


可见 NumPy 的 random 模块效率优势非常明显,基本是 Python 内置模块 random 的 100 倍以上,因此此处推荐使用 numpy.random.randint()函数来生成随机数。我们了解下它构造函数和基本的使用方法:


numpy.random.randint(low, high=None, size=None, dtype=’l’)


  • 返回随机整数,范围区间为[low,high],包含 low,不包含 high

  • 参数:low 为最小值,high 为最大值,size 为数组维度大小,dtype 为数据类型,默认的数据类型是 np.int

  • high 没有填写时,默认生成随机数的范围是[0,low]


print("np.random.randint:\n {}".format(np.random.randint(1,size=5)))# 返回[0,1)之间的整数,所以只有0"""np.random.randint: [0 0 0 0 0]"""print("np.random.randint:\n {}".format(np.random.randint(1,5)))# 返回1个[1,5)时间的随机整数"""np.random.randint: 2"""print("np.random.randint:\n {}".format(np.random.randint(-5,5,size=(2,2))))"""np.random.randint: [[-5 -3] [ 2 -3]]"""
复制代码


注:需要说明的是 random 模块产生的随机数是伪随机数,依赖于特殊算法和指定不确定因素(种子 seed)来实现的,不过这并不妨碍我们进行实验。


3. 预知随机漫步的规律

有研究称股票每天的价格变动就像醉汉行走一样不可预知,接下来我们用 Python 来重现醉汉的随机漫步。


我们假设一名喝醉了酒的醉汉,从一个路灯下开始漫无目的地行走,每一步即可能前进也可能后退也可能拐弯。那么经过一定时间之后,这名醉汉的位置在哪里呢?为了便于理解,我们将醉汉的移动简化为一维的移动,规定他只能在一条直线上随机前进或者后退。


我们使用上文提到的 numpy.random.randint()函数来产生 2000 个随机数,作为随机游走的路线,实现代码如下所示:


draws = np.random.randint(0, 2, size=2000)print(f'random walk direction is {draws}')#random walk direction is [1 0 1 ... 0 1 0]
复制代码


然后我们使用 matplotlib.pyplot.plot()函数绘制出醉汉从 0 轴开始随机游走 2000 步的模拟轨迹图形,如图 1-1 所示:



图 1-1


从中可知在 2000 次漫步中,终点的距离为 32,第 1595 步前进最远的距离为 64,第 142 步后退最远的距离为-25。我们把随机漫步轨迹的计算封装为函数 random_walk(),此处分享实现的代码,如下所示:


def draw_random_walk():    walk_steps = 2000    walk_path = random_walk(walk_steps)
# 统计漫步过程中,终点、前进和后退最大的距离 start_y = 0 start_x = 0 end_y = walk_path[-1] end_x = walk_steps-1
max_y = walk_path.max() max_x = walk_path.argmax()
min_y = walk_path.min() min_x = walk_path.argmin()
x = np.linspace(0, 2000, num=2000)
# 绘制出漫步的足迹 plt.plot(x, walk_path, color='b', linewidth=1, label='walk step')
# 添加标注 # 起点坐标 plt.annotate( 'start:({},{})'.format(start_x, start_y), xy = (start_x,start_y), xycoords='data', xytext=(+50, +20), textcoords='offset points', fontsize=8, bbox=dict(boxstyle='round,pad=0.5',fc ='yellow', alpha = 0.5), arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=.2") )
# 终点坐标 plt.annotate( 'end:({},{})'.format(end_x, end_y), xy = (end_x,end_y), xycoords='data', xytext=(-50, +20), textcoords='offset points', fontsize=8, bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5), arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=.2") )
# 最大距离坐标 plt.annotate( 'max:({},{})'.format(max_x,max_y), xy = (max_x,max_y), xycoords = 'data', xytext = (-20, +20), textcoords='offset points', fontsize = 8, bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5), arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=.2") ) # 最小距离坐标 plt.annotate( 'min:({},{})'.format(min_x,min_y), xy = (min_x,min_y), xycoords = 'data', xytext = (-20, +20), textcoords='offset points', fontsize = 8, bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5), arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=.2") ) plt.legend(loc='best') plt.xlabel('游走步数') plt.ylabel('分布轨迹') plt.title(u"模拟随机漫步") plt.show()
复制代码


由于醉汉的每一步都是完全随机的,因此他最终准确的位置无法被预测出,就像每天的股票价格变动一样是不可预知的。但是,量化交易会从统计学的角度去分析问题,我们用 1000 次随机漫步来模拟醉汉从 0 轴开始 1000 次随机游走 2000 步的模拟轨迹图形,如图 1-2 所示:



图 1-2


从统计学的角度来看,这名醉汉最终的位置的概率分布却是可以计算出来的。图中我们直观地观察出随机游走的发展情况,每一条淡淡的蓝线就是一次模拟,横轴为行走的步数,纵轴表示离开起始点的位置。蓝色越深,就表示醉汉在对应行走了对应的步数之后,出现在此位置的概率越大,可见随着醉汉可能出现的位置的范围不断变大,但是距离起始点越远的位置概率越小。


于是我们联想到正态分布。正态分布是连续随机变量概率分布的一种,也称“常态分布”、“高斯分布”(Gaussian distribution),最早的正态分布概念其实是由德国的数学家和天文学家阿伯拉罕·德莫弗尔(Abraham de Moivre)于 1733 年首次提出的,但由于德国数学家 Gauss 率先将其应用于天文学家研究,故正态分布又叫高斯分布。


正态分布描述的是某件事出现不同结果的概率分布情况,它的概率密度曲线的形状是两头低,中间高,左右对称呈钟型,与我们模拟的随机漫步图很相似。接下来我们继续验证,使用 matplotlib.pyplot 库中的 hist()函数将随机漫步的位置绘制为直方图。如图 1-3 所示:



图 1-3


从图中的显示可知醉汉的行走轨迹在一定意义上是符合正态分布的。可见正态分布现象在现实中意义重大,在自然界、人类社会、心理学等领域的大量现象中都服从或者近似服从正态分布,比如人们能力的高低,身高、体重等身体的状态,学生成绩的好坏,人们的社会态度、行为表现等等。不禁感慨道:数学的奇妙之处就在于,我们可以把不可预知性变为可预知。


4. 总结

金融证券市场一直充满了随机性,但是量化交易的精髓就是用数学公式来精确计算真实的概率分布,以应对不确定性。量化交易的鼻祖级大神爱德华·索普就是利用这种随机游走模型的思想,推算出认股权证在合约兑现的那一天相对应的股票的价格的概率分布,从而计算出当前认股权证的价格是过高还是过低,然后再利用凯利公式,进行买卖。笔者以模拟随机漫步为切入点将文中用 Python 分析金融数据的方法分享给大家,希望能够对大家有所启发。


作者介绍

元宵大师,Python 高级工程师,公众号《元宵大师带你用 Python 量化交易》作者,致力于推动人工智能在金融量化交易领域中的应用。


2019 年 6 月 13 日 08:057283

评论

发布
暂无评论
发现更多内容

IPFS云算力挖矿系统开发技术

薇電13242772558

区块链 IPFS

数字货币交易所开发源码,场外币币交易平台搭建

WX13823153201

数字货币交易所开发

TCP性能分析与调优策略

云流

程序员 计算机网络 网络协议

可以解除程序员中年危机的职业规划

Java架构师迁哥

cglib入门后篇

Rayjun

Java cglib

从零到千万用户,我是如何一步步优化MySQL数据库的?

冰河

数据库 架构 性能优化 分布式数据库 分布式存储

Redis基础—了解Redis是如何做数据持久化的

云流

数据库 redis 编程 计算机

Pulsar Summit Asia 2020 中文专场议题出炉!

Apache Pulsar

大数据 开源 Apache Pulsar

《迅雷链精品课》第二课:区块链核心技术框架

迅雷链

区块链

从一场“众盟科技云滇之播”,我们发现了美食直播的商业与公益价值

人称T客

【T1543.003】利用 ACL 隐藏恶意 Windows 服务

比伯

Java 大数据 编程 架构 计算机

anyRTC Flutter SDK :全面实现跨平台音视频互动

anyRTC开发者

音视频 WebRTC RTC sdk 安卓

马士兵老师首推Java七条自学路线,自学到底能不能行?自学也能拿到40W年薪?

Java架构追梦

Java 架构 面试 马士兵 项目实战

当代开发者的六大真实现状,你被哪一个场景“戳中”了?

华为云开发者社区

开发者 调研 报告

简要分析近几年商业软件开发平台的现状

Philips

敏捷开发 快速开发 企业应用

阿里顶级DBA专家团又一力作——MySQL8的150高效技巧

周老师

Java 编程 程序员 架构 面试

涨薪神作!华为内部操作系统与网络协议笔记爆火,Java程序员有福了

Java架构之路

Java 程序员 面试 编程语言

完美!阿里P8都赞不绝口的世界独一份489页SQL优化笔记

Java~~~

Java 数据库 程序员 架构师 SQL优化

非线性声学回声如何破解?华为云硬核技术为你解决

华为云开发者社区

算法 音视频 音视频算法

JVM真香系列:轻松掌握JVM运行时数据区

田维常

JVM

LeetCode题解:剑指 Offer 22. 链表中倒数第k个节点,使用数组,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

Docker

数字人民币都来了 黄金还有什么用?

CECBC区块链专委会

数字货币

区块链产业,怎样“链”住未来?

CECBC区块链专委会

区块链

Java垃圾回收GC概览

Java JVM GC

【算法题目解析】杨氏矩阵数字查找

程序员架构进阶

算法 二分查找 杨氏矩阵

Java程序员必备,Github上星标55.9k的微服务神级笔记简直太香了,学完感觉自己又行了!

Java架构之路

Java 程序员 架构 面试 编程语言

京东技术中台Flutter实践之路(二)

京东科技开发者

开源 中台 大前端 Web UI

阿里云视频云实时字幕技术,助力英雄联盟S10全球总决赛

阿里云视频云

游戏开发 直播 语音识别 字幕

把最新JAVA面试真题(阿里/字节跳动/美团)整理出来,却被自己菜哭了,赶紧去刷题了

Java架构追梦

Java 阿里巴巴 架构 面试 面试题

云计算简史(完整版)

明道云

演讲经验交流会|ArchSummit 上海站

演讲经验交流会|ArchSummit 上海站

股票价格在随机漫步吗?用Python来告诉你-InfoQ