Python 揭秘斐波那契定律,如何幫助碼農分析股票?| 技術頭條
作者 | 元宵大師
責編 | 胡巍巍
剖析斐波那契數列
對於斐波那契數列相信大家並不陌生,它指的是這樣一個數列:0、1、1、2、3、5、8、13、21、34、55、89、144、233…………這個數列究竟蘊含著什麼秘密呢?我們從以下三個問題展開對斐波那契數列的剖析:
(1) 斐波那契數列是怎麼由來的?
斐波那契數列是由義大利中世紀數學家斐波那契(Fibonacci,公元1175-1240)在他1202年著作的《算盤書》(Liber Abaci)中以兔子繁殖為例子所引出的。
在書中提出了一個有趣的問題:假設一對剛出生的小兔一個月後就能長成大兔,再過一個月就能生下一對小兔,並且此後每個月都生一對小兔,一年內沒有發生死亡,那麼一對剛出生的兔子,在一年內繁殖成多少對兔子?
依照假定條件計算,第一個月是一對兔子,第二個月長成了大兔,第三個月生下一對小兔總共由兩對兔子……
在並不知曉斐波那契數列隱含的規律情況下,我們手動推算得到了一年內兔子繁殖的情況,如下圖所示:
由該繁衍規律得到的每個月兔子的數量組成了斐波那契數列,因此也稱為「兔子數列」。
發生在18世紀中期的澳大利亞野兔成災的故事體現了真實版的「兔子數列」驚人的增長速度。
當時英國殖民者為了滿足自己的狩獵愛好把歐洲野兔引進了澳大利亞,由於澳大利亞氣候溫暖、牧草豐富,為兔子提供了良好的生存條件,加上澳大利亞本土缺乏猛禽、黃鼠狼等兔子的天敵,兔子開啟了斐波那契數列式的增長,當時澳大利亞的生態遭到了嚴重破壞,繼而開始了人兔大戰……接下來讓我們逐步揭開斐波那契數列的秘密。
(2) 斐波那契數列的規律是什麼?
從[0、1、1、2、3、5、8、13、21、34、55、89、144、233…………]這個序列中可以發現,第一個元素為0,第二個元素為1,之後的每一個元素為之前兩個元素之和。在數學上,我們可以用遞歸的方法來定義斐波納契數列的生成規律,如下所示:
當n=0時,F(n)=0
當n=1時,F(n)=1
當n>1時,F(n)= F(n-1)+ F(n-2)
(3) 斐波那契數列神奇之處在哪?
斐波那契數列存在許多神奇的性質,我們不妨對斐波那契數列中相鄰的兩個數求商值。當前一個數值除以後一個數值時可以得到以下的結果:
0 ÷ 1 = 0
1 ÷ 1 = 1
1 ÷ 2 = 0.5
2 ÷ 3 = 0.6666…
3 ÷ 5 = 0.6
5 ÷ 8 = 0.625
8 ÷ 13 = 0.615…
13 ÷ 21 = 0.619…
21 ÷ 34 = 0.617…
34 ÷ 55 = 0.618…
55 ÷ 89 = 0.617…
89 ÷ 144 = 0.618…
144 ÷ 233 = 0.618…
……
我們注意到從21除以34開始以至於到數列的無窮大,商值是趨於0.618的一個無理數!
反過來當後一個數值除以其前面的數值時得到的結果如下所示:
1 ÷ 0 = 0
1 ÷ 1 = 1
2 ÷ 1 = 2
3 ÷ 2 = 1.5
5 ÷ 3 = 1.67
8 ÷ 5 = 1.6
13 ÷ 8 = 1.625
21 ÷ 13 = 1.615…
34 ÷ 21 = 1.619…
55 ÷ 34 = 1.618…
89 ÷ 55 = 1.618…
144 ÷ 89 = 1.618…
相應的從34除以21開始直到數列無窮大,商值是趨於1.618的一個無理數!0.618與1.618彼此出奇的互為倒數,並且0.618這個數值正是有名的「黃金分割」比例!這也是斐波那契數列又稱為黃金分割數列的原因。
實際上黃金分割的提出要遠早於斐波那契數列。假設線段總長為1,在線段上找到一個黃金分割點,將線段分割為A和B兩部分,B的長度為x,A的長度為1-x,如下圖所示:
A與B的長度之比等於B與全長的比,這個比例就為黃金分割,比例關係如下所示:
對該公式進行轉換,並求出x值,如下所示:
於是B與全長的比為0.618,B與A的長度比為1.618,實際上它們指的是同樣線段的黃金分割比例。
Python驗證數列的神奇
對於枯燥而繁瑣的計算類工作理應交給Python來做!上文提到斐波納契數列的生成規律是由遞歸方法來定義的,因此用Python遞歸函數生成數列會更直觀、更容易理解。代碼如下所示:
def Fibonacci_Generate(n):
if n < 0:
print("Input value is error")
return -1
elif n == 0:return 0
elif n == 1:return 1
else:
return Fibonacci_Generate(n-1)+ Fibonacci_Generate(n-2)
分別繪製出包含10項和30項數值的斐波那契數列增長曲線,如下圖所示。
繪製斐波那契數列增長曲線代碼如下所示:
def Fibonacci_sequence(n):
fibs_list =
for i in np.arange(0, n): fibs_list.append(Fibonacci_Generate(i))
plt.plot(np.arange(n), fibs_list, c="g", marker="o", ls="dashed" )
plt.title("Fibonacci sequence:{}".format(n))
plt.show
從圖中斐波那契數列增長形式上可以看出,數列在初期增長緩慢,之後呈現出以1.618為底數的指數增長速度。
雖然使用遞歸函數生成數列優點是定義簡單,邏輯清晰,不過缺點是實現的效率極低,並且深層次遞歸調用時會導致棧溢出。
我們採用Python內置time模塊來測試下遞歸函數生成30項斐波那契數列所開銷時間。分別在代碼的開始和結束處添加time.perf_counter函數,用於返回系統的運行時間,由於返回值的基準點是未定義的,所以只有連續調用的結果之差才是有效的代碼開銷時間。我們測得的執行時間為2.918秒。代碼如下所示:
start = time.perf_counter
for i in np.arange(0, n): fibs_list.append(Fibonacci_Generate(i))
elapsed = (time.perf_counter - start)
print("Time used:", elapsed)#Time used: 2.917980852
理論上,所有的遞歸函數都可以寫成循環的方式,雖然循環的邏輯不如遞歸清晰,但在執行效率上循環優勢明顯,改用循環方式後所測得的執行時間僅僅為16.44微秒。代碼如下所示:
# 使用循環
def Fibonacci_Generate_Loop(n):
if n < 0:
print("Input value is error")
return -1
elif n == 0:return [0]
elif n == 1:return [0,1]
else:
result_list = [0,1]
a, b = 0, 1
for i in range(2, n + 1):
a, b = b, a + b
result_list.append(b)
return result_list
在使用循環方式生成斐波那契數列時,必須要用列表來存儲每次計算得到的數值,為了讓代碼優雅起來,我們可以使用生成器來優化。所謂生成器其實是一種特殊的迭代器,內部支持了迭代器協議。
Python中提供生成器函數和生成器表達式兩種方式實現生成器,每次請求返回一個結果,不需要一次性構建一個結果列表,節省了內存空間。此處我們使用生成器函數方式實現生成器,這種方式編寫為常規的def語句,使用yield語句一次返回一個結果,在每個結果之間掛起和繼續它們的狀態。代碼如下所示:
# 使用iterrows
def Fibonacci_Generate_iter(n):
if n < 0:
print("Input value is error")
return -1
elif n == 0:return [0]
elif n == 1:return [0,1]
else:
a, b = 0, 1
yield a
yield b
for i in range(2, n + 1):
a, b = b, a + b
yield b
上文還提到了斐波那契數列前一個數值除以後一個數值時,隨著數列的增長,商值為是趨於0.618的一個無理數。接下來我們用Python驗證一下。實現代碼如下所示:
def Fibonacci_divide(seq):
div_list =
for i in np.arange(0, len(seq)-1):
div_list.append(seq[i]/seq[i+1])
plt.plot(np.arange(len(div_list)), div_list, c="g", marker="o", ls="dashed" )
plt.title("Fibonacci Fn/Fn+1:{}".format(div_list[-1]))
plt.show
Fibonacci_divide(list(Fibonacci_Generate_iter(100)))
我們得到了斐波那契數列的Fn/Fn+1的前100項的結果,如下圖所示。從圖中可知,第八項與第九項的比值開始,之後的數值都趨於0.618左右。
因此再一次驗證得到斐波那契數列是近似指數增長的形式,為了更確切的說明這個問題,我們看一下由數學家比內建立的斐波那契數列的通項公式,如下所示:
由通項公式計算Fn/Fn+1的結果依然是0.618,如下所示:
黃金分割率分析股價
斐波那契數列是大自然的一個基本屬性,尤其是數列中的黃金分割比例部分,它出現在繪畫、雕塑、建築等多個領域,人們不約而同地認為黃金分割比例是最完美的。
比如「斷臂的維納斯」雕塑,身高2.02米,她的肚臍正是黃金分割點,肚臍以上部分和肚臍以下部分之比接近於0.618。可見黃金分割比例是作用在人們潛意識中的一種客觀規律,有著極強的自然屬性,當然也包括在股市的分析中:股價一直遵循著高低相間的運行規律。
當股價走勢出現反轉時極有可能在黃金分割比例0.382、 0.618上遇到暫時的阻力或支撐,因此通過黃金分割比例尋找出上漲/下跌趨勢中的壓力位和支撐位,有助於交易者更好地判斷「入場」和「出場」的時機。
接下來以股票「新希望」的歷史數據為例,尋找股價的支撐位和壓力位。「新希望」 2019年1月至2019年6月的走勢圖如下所示:
通常股價的拉升不會一步到位,大多採用螺旋式上漲,也就是說在新的上漲前,要有一波回撤,洗去浮動的籌碼來蓄勢待發,而回撤的幅度恰好符合黃金分割的比例0.618。
「新希望」這半年期間股價呈上漲趨勢,中途有幾次短暫的回撤走勢,我們用黃金分割比例來計算下回撤的位置。計算公式為(最大值-最小值)*黃金分割比例+最小值,實現方法如下所示:
Fib_max = df_stockload.Close.max
Fib_maxid = df_stockload.index.get_loc(df_stockload.Close.idxmax)
Fib_min = df_stockload.Close.min
Fib_minid = df_stockload.index.get_loc(df_stockload.Close.idxmin)
Fib_382 = (Fib_max - Fib_min) * 0.382 + Fib_min
Fib_618 = (Fib_max - Fib_min) * 0.618 + Fib_min
接下來驗證黃金分割比例判斷支撐/阻力位的有效性,如下圖所示,第一輪迴撤位置正好在黃金分割率0.618所處位置,即11.61。
總結
本文以股價分析為應用場景介紹了斐波那契數列的神奇特徵,儘管斐波那契的黃金分割線可以幫助交易者提高判斷支撐位或阻力位的成功率。
但和其他的技術分析工具一樣,它也存在一定的局限性,比如單純以波段高點和波段低點的差值作為基準這個方式,在波動較大或者區間震蕩持續較久的行情下可靠性會降低,改進的方法可以將股價按序列值大小排序,取黃金分割比例所對應位置上的序列值,這樣可靠性會更高。
作者簡介:元宵大師,Python高級工程師,致力於推動人工智慧、大數據分析在金融量化交易領域中的應用。歡迎大家關注我的個人公眾號《元宵大師帶你用Python量化交易》。
【End】


※Chrome成為互聯網看門人!
※天數智芯斬獲斯坦福大學DAWNBench深度學習推理榜單冠軍
TAG:CSDN |