股票價格在隨機漫步嗎?用 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 列表,以此來了解下它們之間具體的性能差距。實現代碼如下所示:

複製代碼

<code>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/<code>

可見 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]

複製代碼

<code>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]]"""/<code>

注:需要說明的是 random 模塊產生的隨機數是偽隨機數,依賴於特殊算法和指定不確定因素 (種子 seed) 來實現的,不過這並不妨礙我們進行實驗。

3. 預知隨機漫步的規律

有研究稱股票每天的價格變動就像醉漢行走一樣不可預知,接下來我們用 Python 來重現醉漢的隨機漫步。

我們假設一名喝醉了酒的醉漢,從一個路燈下開始漫無目的地行走,每一步即可能前進也可能後退也可能拐彎。那麼經過一定時間之後,這名醉漢的位置在哪裡呢?為了便於理解,我們將醉漢的移動簡化為一維的移動,規定他只能在一條直線上隨機前進或者後退。

我們使用上文提到的 numpy.random.randint() 函數來產生 2000 個隨機數,作為隨機遊走的路線,實現代碼如下所示:

複製代碼

<code>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]/<code>

然後我們使用 matplotlib.pyplot.plot() 函數繪製出醉漢從 0 軸開始隨機遊走 2000 步的模擬軌跡圖形,如圖 1-1 所示:

股票價格在隨機漫步嗎?用 Python 來告訴你

圖 1-1

從中可知在 2000 次漫步中,終點的距離為 32,第 1595 步前進最遠的距離為 64,第 142 步後退最遠的距離為 -25。我們把隨機漫步軌跡的計算封裝為函數 random_walk(),此處分享實現的代碼,如下所示:

複製代碼

<code>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()/<code>

由於醉漢的每一步都是完全隨機的,因此他最終準確的位置無法被預測出,就像每天的股票價格變動一樣是不可預知的。但是,量化交易會從統計學的角度去分析問題,我們用 1000 次隨機漫步來模擬醉漢從 0 軸開始 1000 次隨機遊走 2000 步的模擬軌跡圖形,如圖 1-2 所示:

股票價格在隨機漫步嗎?用 Python 來告訴你

圖 1-2

從統計學的角度來看,這名醉漢最終的位置的概率分佈卻是可以計算出來的。圖中我們直觀地觀察出隨機遊走的發展情況,每一條淡淡的藍線就是一次模擬,橫軸為行走的步數,縱軸表示離開起始點的位置。藍色越深,就表示醉漢在對應行走了對應的步數之後,出現在此位置的概率越大,可見隨著醉漢可能出現的位置的範圍不斷變大,但是距離起始點越遠的位置概率越小。

於是我們聯想到正態分佈。正態分佈是連續隨機變量概率分佈的一種,也稱“常態分佈”、“高斯分佈”(Gaussian distribution),最早的正態分佈概念其實是由德國的數學家和天文學家阿伯拉罕·德莫弗爾 (Abraham de Moivre) 於 1733 年首次提出的,但由於德國數學家 Gauss 率先將其應用於天文學家研究,故正態分佈又叫高斯分佈。

正態分佈描述的是某件事出現不同結果的概率分佈情況,它的概率密度曲線的形狀是兩頭低,中間高,左右對稱呈鍾型,與我們模擬的隨機漫步圖很相似。接下來我們繼續驗證,使用 matplotlib.pyplot 庫中的 hist() 函數將隨機漫步的位置繪製為直方圖。如圖 1-3 所示:

股票價格在隨機漫步嗎?用 Python 來告訴你

圖 1-3

從圖中的顯示可知醉漢的行走軌跡在一定意義上是符合正態分佈的。可見正態分佈現象在現實中意義重大,在自然界、人類社會、心理學等領域的大量現象中都服從或者近似服從正態分佈,比如人們能力的高低,身高、體重等身體的狀態,學生成績的好壞,人們的社會態度、行為表現等等。不禁感慨道:數學的奇妙之處就在於,我們可以把不可預知性變為可預知。

4. 總結

金融證券市場一直充滿了隨機性,但是量化交易的精髓就是用數學公式來精確計算真實的概率分佈,以應對不確定性。量化交易的鼻祖級大神愛德華·索普就是利用這種隨機遊走模型的思想,推算出認股權證在合約兌現的那一天相對應的股票的價格的概率分佈,從而計算出當前認股權證的價格是過高還是過低,然後再利用凱利公式,進行買賣。筆者以模擬隨機漫步為切入點將文中用 Python 分析金融數據的方法分享給大家,希望能夠對大家有所啟發。


分享到:


相關文章: