實戰:基於技術分析的Python算法交易

2020-12-17 AI科技大本營

譯者 | Tianyu

本文是用 Python 做交易策略回測系列文章的第四篇。上個部分介紹了以下幾個方面內容:

介紹了 zipline 回測框架,並展示了如何回測基本的策略導入自定義的數據並使用 zipline評估交易策略的表現這篇文章的目的是介紹如何基於技術分析(TA, Technical Analysis)來創建交易策略。在此引用維基百科的解釋,技術分析是指「基於對市場的歷史數據、成交價格、交易量的研究,來預測價格走勢的一套方法」。

在本文中,我會介紹如何使用流行的 Python 庫 TA-Lib 以及 zipline 回測框架來計算 TA 指標。我會創建 5 種策略,然後研究哪種策略在投資期限內表現最好。

安裝

我用到的庫有以下幾個:

pyfolio 0.9.2

numpy 1.14.6

matplotlib 3.0.0

pandas 0.22.0

json 2.0.9

empyrical 0.5.0

zipline 1.3.0

輔助函數

在構造策略之前,我要先定義幾個輔助函數(此處我只介紹其中一個,因為它是最重要的一個)。

這個函數用來設置回測的起始時間,因為我希望所有策略開始實施的時間保持一致,設置為2016年的第一天。不過,有些基於技術指標的策略需要一定數量的歷史數據,也就是所謂的 warm-up 階段。請一定記住一點,沒有任何交易決策會發生在回測期的起始時間之前。

def get_start_date(ticker, start_date, days_prior):

start_date_dt = datetime.strptime(start_date, '%Y-%m-%d')

prior_to_start_date_dt = start_date_dt - relativedelta(days=2 * days_prior)

prior_to_start_date = prior_to_start_date_dt.strftime('%Y-%m-%d')

yahoo_financials = YahooFinancials(ticker)

df = yahoo_financials.get_historical_price_data(

prior_to_start_date, start_date, 'daily')

df = pd.DataFrame(df[ticker]['prices'])['formatted_date']

if df.iloc[-1] == start_date:

days_prior += 1

new_start_date = df.iloc[-days_prior]

return new_start_date

策略

本篇文章中,我們要解決的問題如下:

投資者有 10000 元的本金投資時限為 2016-2017投資者僅投資 Tesla 的股票假設不存在交易成本,即交易佣金為零不存在做空行為(投資者只能出售他們擁有的股票)當投資者購買股票時,他們會花掉全部本金之所以選擇這段時期,是因為2018年中後的 Quandl 數據集還沒有更新,我們希望代碼可以儘可能簡化。關於如何將數據載入 zipline 的更多細節,請參考到我之前的文章。

買入和持有的策略

我們首先來看最基本的策略 —— 買入和持有。具體的思路是,我們買入一定的資產,在整個投資期間不進行任何操作。因此在投資第一天,我們使用全部本金儘可能多地購買 Tesla 的股票,接下來什麼事情都不做。

這種簡單的策略可以作為其他高級策略的基準,若某種複雜的策略相比於基準策略反而損失了更多的錢,那麼說明這種策略毫無用處。

%%zipline --start 2016-1-1 --end 2017-12-31 --capital-base 10000.0 -o buy_and_hold.pkl

# imports

from zipline.api import order_percent, symbol, record

from zipline.finance import commission

# parameters

SELECTED_STOCK = 'TSLA'

def initialize(context):

context.asset = symbol(SELECTED_STOCK)

context.has_ordered = False

context.set_commission(commission.PerShare(cost=0.0, min_trade_cost=0))

def handle_data(context, data):

# trading logic

if not context.has_ordered:

order_percent(context.asset, 1)

context.has_ordered = True

record(price=data.current(context.asset, 'price'))

接下來,我們載入有關該策略表現的 DataFrame:

buy_and_hold_results = pd.read_pickle('buy_and_hold.pkl')

這裡可能會出現 ending_cash 為負的情況,原因是我們想要買入的股份是當天收盤時計算的,於是使用的是收盤價格。然而,這筆交易是次日執行的,價格可能會發生大幅變化。在 zipline 中,交易不會因為金額不足而被拒,但我們可以通過負的餘額將其終止。我們可以想些辦法避免這種情況的發生,例如手動計算第二天要買入的股份,並考慮股價上漲等因素,以防止這種情況發生。

我們使用一個輔助函數,將該策略的細節進行可視化:投資組合的變化,交易價格序列,以及每天的收益情況。

我們還使用了另一個輔助函數來觀察策略的表現,該函數將用於最後一部分:

buy_and_hold_results = pd.read_pickle('buy_and_hold.pkl')

為了簡潔起見,我們不會展示每種策略的全部步驟,因為它們的執行方式都是一樣的。

簡單的移動平均策略

我們採用的第二種策略基於簡單的移動平均數方法(SMA, Simple Moving Average)。該策略的邏輯可以歸納為以下幾步:

當20天的 SMA 價格上升時,買入股份當20天的 SMA 價格下降時,賣掉全部股份用前19天和當天的數據計算移動平均數,次日執行交易決策這是我們第一次調用預設輔助函數的地方,計算起始日期,以使投資者能在2016年的第一個交易日制定交易決策。

get_start_date('TSLA', '2016-01-04', 19)# '2015-12-04'

在下面的策略中,我們使用修改後的日期作為起始日期:

%%zipline --start 2015-12-4 --end 2017-12-31 --capital-base 10000.0 -o simple_moving_average.pkl

# imports

from zipline.api import order_percent, record, symbol, order_target

from zipline.finance import commission

# parameters

MA_PERIODS = 20

SELECTED_STOCK = 'TSLA'

def initialize(context):

context.time = 0

context.asset = symbol(SELECTED_STOCK)

context.set_commission(commission.PerShare(cost=0.0, min_trade_cost=0))

context.has_position = False

def handle_data(context, data):

context.time += 1

record(time=context.time)

if context.time < MA_PERIODS:

return

price_history = data.history(context.asset, fields="price", bar_count=MA_PERIODS, frequency="1d")

ma = price_history.mean

# cross up

if (price_history[-2] < ma) & (price_history[-1] > ma) & (not context.has_position):

order_percent(context.asset, 1.0)

context.has_position = True

# cross down

elif (price_history[-2] > ma) & (price_history[-1] < ma) & (context.has_position):

order_target(context.asset, 0)

context.has_position = False

record(price=data.current(context.asset, 'price'),

moving_average=ma)

注意:data.current(context.asset, 『price』) 等同於 price_history[-1].

下圖展示了該策略:

下圖展示了20天的移動平均價格序列。我們還對每一次交易做了標註,即在記號之後的第一個交易日執行此筆交易。

移動平均交叉

移動平均交叉策略(Moving Average Crossover)可以看作是上一種策略的拓展版,用兩個不同規格的移動窗口來代替單個的窗口。100天的移動平均數序列中,要隔很久才會出現價格的突變,而20天的移動平均數序列發生突變的速度要快很多。

該策略的邏輯如下:

當較快的移動平均值穿越較慢的移動平均值時,我們買入股份當較慢的移動平均值穿越較快的移動平均值時,我們賣出股份一定要記住一點,在這種策略中,許多不同長度窗口的組合構成了速度不同的移動平均數。

對於該策略,我們需要另外載入100天的數據,以便於準備 warm-up 階段。

%%zipline --start 2015-8-11 --end 2017-12-31 --capital-base 10000.0 -o moving_average_crossover.pkl

# imports

from zipline.api import order_percent, record, symbol, order_target

from zipline.finance import commission

# parameters

SELECTED_STOCK = 'TSLA'

SLOW_MA_PERIODS = 100

FAST_MA_PERIODS = 20

def initialize(context):

context.time = 0

context.asset = symbol(SELECTED_STOCK)

context.set_commission(commission.PerShare(cost=0.0, min_trade_cost=0))

context.has_position = False

def handle_data(context, data):

context.time += 1

if context.time < SLOW_MA_PERIODS:

return

fast_ma = data.history(context.asset, 'price', bar_count=FAST_MA_PERIODS, frequency="1d").mean

slow_ma = data.history(context.asset, 'price', bar_count=SLOW_MA_PERIODS, frequency="1d").mean

# Trading logic

if (fast_ma > slow_ma) & (not context.has_position):

order_percent(context.asset, 1.0)

context.has_position = True

elif (fast_ma < slow_ma) & (context.has_position):

order_target(context.asset, 0)

context.has_position = False

record(price=data.current(context.asset, 'price'),

fast_ma=fast_ma,

slow_ma=slow_ma)

接下來,我們繪製了兩個移動平均價格序列。我們可以發現,該策略產生的交易行為要比 SMA 策略少得多。

移動平均線收斂差異

MACD 的全稱為 Moving Average Convergence/Divergence,即移動平均線收斂差異指標,是一種常用於股價技術分析中的指標。

MACD 由三個時間序列構成:

MACD 序列:快速(短期)和慢速(長期)的兩個指數移動平均值的差值信號序列:MACD 序列的 EMA(指數移動平均值)差異序列:MACD 序列與信號序列之間的差值MACD 的參數包括計算三個移動平均數的天數,即 MACD(a, b, c),參數 a 表示快速 EMA,b 表示慢速 EMA,c 表示 MACD 序列的 EMA。最常見的參數配置為 MACD(12, 26, 9),也是本文所採用的配置。若每周有6個工作日,這三個參數分別對應2個星期、1個月、1.5個星期。

必須記住一點,由於 MACD 是基於移動平均方法進行計算的,因此它是一種滯後指標。這就解釋了為什麼 MACD 在股市上的作用很小,它無法得出準確的價格趨勢。

該策略的基本思想如下:

當 MACD 線穿越信號線向上時,買入股份當 MACD 線穿越信號線向下時,賣出股份和之前一樣,為了準備 warm-up,我們要保證有34個歷史數據值來計算 MACD:

%%zipline --start 2015-11-12 --end 2017-12-31 --capital-base 10000.0 -o macd.pkl

# imports ----

from zipline.api import order_target, record, symbol, set_commission, order_percent

import matplotlib.pyplot as plt

import talib as ta

from zipline.finance import commission

# parameters ----

SELECTED_STOCK = 'TSLA'

#initialize the strategy

def initialize(context):

context.time = 0

context.asset = symbol(SELECTED_STOCK)

context.set_commission(commission.PerShare(cost=0.0, min_trade_cost=0))

context.has_position = False

def handle_data(context, data):

context.time += 1

if context.time < 34:

return

price_history = data.history(context.asset, fields="price", bar_count=34, frequency="1d")

macd, macdsignal, macdhist = ta.MACD(price_history, 12, 26, 9)

if (macdsignal[-1] < macd[-1]) and (not context.has_position):

order_percent(context.asset, 1.0)

context.has_position = True

if (macdsignal[-1] > macd[-1]) and (context.has_position):

order_target(context.asset, 0)

context.has_position = False

record(macd = macd[-1], macdsignal = macdsignal[-1], macdhist = macdhist[-1], price=price_history[-1])

接下來,我們繪製了 MACD 線和信號線,交叉點代表買入/賣出的信號。另外,你也可以試著用直方圖的形式來展現 MACD 差異。

相對強弱指標(RSI)

RSI 的全稱為 Relative Strength Index,即相對強弱指標,也是一種用於創建交易策略的技術指標。RSI 被看作是一種動量振蕩器,它可以估測價格變化的速度和幅度。

RSI 指標評估了股價的向上力量與向下力量的比率。若向上的力量較大,則計算出來的指標上升;若向下的力量較大,則指標下降。

RSI 的結果為0到100之間的數字,一般按14天進行計算。為生成交易信號,通常要指定 RSI 的下限為30,上限為70。也就是說,30以下在超賣區,70以上為超買區。

有時候,也可能會設定一個比較居中的值,比如在涉及到做空的策略中。我們也可以選擇更極端的閾值,如20和80。不過,這要求具備專業知識,或者在回測時嘗試。

這種策略的思想如下:

當 RSI 低於下限(30)時,買入股份當 RSI 高於上限(70)時,賣出股份%%zipline --start 2015-12-10 --end 2017-12-31 --capital-base 10000.0 -o rsi.pkl

# imports ----

from zipline.api import order_target, record, symbol, set_commission, order_percent

import matplotlib.pyplot as plt

import talib as ta

from zipline.finance import commission

# parameters ----

SELECTED_STOCK = 'TSLA'

UPPER = 70

LOWER = 30

RSI_PERIOD = 14

#initialize the strategy

def initialize(context):

context.time = 0

context.asset = symbol(SELECTED_STOCK)

context.set_commission(commission.PerShare(cost=0.0, min_trade_cost=0))

context.has_position = False

def handle_data(context, data):

context.time += 1

if context.time < RSI_PERIOD + 1:

return

price_history = data.history(context.asset, fields="price", bar_count=RSI_PERIOD+1, frequency="1d")

rsi = ta.RSI(price_history, timeperiod=RSI_PERIOD)

if rsi[-1] < LOWER and not context.has_position:

order_percent(context.asset, 1.0)

context.has_position = True

if rsi[-1] > UPPER and context.has_position:

order_target(context.asset, 0)

context.has_position = False

record(rsi=rsi[-1], price=price_history[-1], time=context.time)

下圖繪製了 RSI 指標和上、下限:

效果評估

最後一步,把所有的評估指標放入一個 DataFrame 中,然後觀察其結果。我們會發現在回測時,基於簡單移動平均方法的策略在收益方面表現最好,其夏普指數也最高,即在特定風險下,可獲得的收益最高。基於 MACD 的策略排在第二位。只有這兩種策略的表現超過了我們所設置的基準。

perf_df = pd.DataFrame({'Buy and Hold': buy_and_hold_perf,

'Simple Moving Average': sma_perf,

'Moving Average Crossover': mac_perf,

'MACD': macd_perf,

'RSI': rsi_perf})

perf_df.transpose

結論

本篇文章介紹了如何利用 zipline 和 talib 進行交易策略的回測,使用的技術指標包括移動平均數、MACD、RSI 等等。但這只是一些基礎,還有相當多更加複雜的策略。

另外,我們必須記住一點,一些在過去表現很好的策略不一定也適用於未來。

(*本文為AI科技大本營編譯文章,轉載請微信聯繫 1092722531)

相關焦點

  • 算法基礎:五大排序算法Python實戰教程
    算法基礎:五大排序算法Python實戰教程排序算法的複雜度排序是每個軟體工程師和開發人員都需要掌握的技能。不同的排序算法很好地展示了算法設計上如何強烈的影響程序的複雜度、運行速度和效率。讓我們看一下前6種排序算法,看看如何在Python中實現它們!
  • 量化交易之《Python數據分析》
    利用Python庫NetworkX分析網絡 監督學習:要求為訓練數據提供標籤無監督學習:學習算法不需要人工輸入,能夠自行發現數據中存在的模式強化學習:這種類型的學習技術無需要進行輔導,但需要提供一些反饋信息基於邏輯回歸的分類基於支持向量機的分類基於ElasticNetCV的回歸分析支持向量機回歸
  • 基於python的大數據分析-pandas數據讀取(代碼實戰)
    書籍推薦《大話軟體測試》出版啦,內容包括但不限於性能、自動化、接口、安全、移動APP非功能測試、抓包、loadrunner、jmeter、soapui、Appium、python
  • Python視頻教程網課編程零基礎入門數據分析網絡爬蟲全套Python...
    基於liunx系統的python教程,課程裡也有liunx操作的詳細教學,不用擔心學習時不會操作liunx系統。 22機器學習 23深度學習 24數據結構和算法 25python網絡爬蟲 26機器學習入門篇 27機器學習入門篇2 28機器學習提升篇 29數據挖掘篇 30深度學習必備原理與實戰 31深度學習必備原理與實戰2 32深度學習必備原理與實戰3
  • python機器學習預測分析核心算法.pdf
    機器學習關注於預測,其核心是一種基於數學和算法的技術,要掌握該技術,需要對數學及統計概念有深入理解,能夠熟練使用R 語言或者其他程式語言。  本書通過集中介紹兩類可以進行有效預測的機器學習算法,展示了如何使用Python 程式語言完成機器學習任務,從而降低機器學習難度,使機器學習能夠被更廣泛的人群掌握。
  • Python機器學習實戰 —— KNN算法詳解
    這個系列按照機器學習實戰的章節來寫,由於市面上已經有很多同類的文章,一般以介紹算法,貼代碼,舉例子為主,個人讀下來,覺得對於實現的代碼還是不能有很好的理解,所有有了這個系列。要寫這個系列還有三個原因:實戰的代碼是Python2的,有一些用法已經在python3中不支持了,以後的系列都以pyhton3完成,遇到python2不支持的坑,會進行一下對比有一些初級的函數在初學階段是需要積累的,孤立的去記憶比較費時費力,所以一邊學算法的實現,一邊把遇到的一些函數的用法記錄下來~遇到有趣的pythonic的表達,記錄分享出來,做知識積累。
  • python人工智慧項目實戰,PDF+源碼
    我們首先介紹如何使用機器學習和深度學習技術創建智能系統的基礎知識。您將吸收各種神經網絡架構,如CNN,RNN,LSTM,以解決關鍵的新世界挑戰。您將學習如何訓練模型以檢測人眼中的糖尿病視網膜病變狀況,並創建用於執行視頻到文本翻譯的智能系統。您將在醫療保健領域中使用轉移學習技術,並使用GAN實施樣式轉移。
  • 機器學習在證券演算法交易中的應用 — 技術分析篇
    關注MultiCharts,了解更多量化與交易知識 技術分析是基於價格而做出的分析
  • python金融風控評分卡模型和數據分析
    (原創課程,版權所有,項目合作QQ:231469242,微信公眾號:pythonEducation) 課程介紹python金融風控評分卡模型和數據分析微專業課包含《python信用評分卡建模(附代碼)》,《python風控建模實戰lendingClub》,《金融現金貸用戶數據分析和畫像》三套課程系列
  • 超適合Python小白的乾貨,Python數據分析50個實戰項目
    ——人力資源分析9.大眾點評評論文本挖掘10.手機微博榜單數據爬蟲與分析11.貓眼電影爬蟲及分析12.漫威電影宇宙英雄綜合實力對比分析13.20 秒看懂中國大學 10 年排行榜變化14.航空公司客戶價值分析15.電子商務網站用戶行為分析及服務推薦16.關於地震的爬蟲數據分析實戰
  • 那些有趣/用的 Python 庫,15篇 Python 技術熱文
    《Python 爬蟲實戰:股票數據定向爬蟲》本文爬蟲實戰目標是運用python3.5, 獲取上交所和深交所所有股票的名稱和交易信息,輸出到保存文件中。學習Python爬蟲的初學者可以看過來。《10 種機器學習算法的要點(附 Python 和 R 代碼)》本文為那些有追求的數據科學家和機器學習狂熱者們,簡化學習旅途。這篇指南會讓你動手解決機器學習的問題,並從實踐中獲得真知。我提供的是幾個機器學習算法的高水平理解,以及運行這些算法的 R 和 Python 代碼。這些應該足以讓你親自試一試了。
  • 交易思路詳解:利用程序化算法EA數學模型中的賠率與概率!趨勢博弈算法交易策略模型!
    採用多策略多組合程序化數學算法模型交易策略!技術問題解決及業務模式解決合作方案提供商!
  • 基於TensorFlow的深度學習實戰
    首先安裝必備軟體:# Ubuntu/Linux 64-bit$ sudo apt-get install python-pip python-dev python-virtualenv # Mac OS X $ sudo easy_install pip$ sudo pip install --upgrade virtualenv
  • 原理+代碼|Python基於主成分分析的客戶信貸評級實戰
    文章來源: 早起Python作者:蘿蔔本文是Python商業數據挖掘實戰的第5篇1 - 基於不平衡數據的反欺詐模型實戰>2 - Apriori算法實現智能推薦3 - 隨機森林預測寬帶客戶離網4 - 多元線性回歸模型實戰5 - PCA實現客戶信貸5C評級
  • Python深度學習:邏輯、算法與編程實戰
    今天為您推薦一本精品圖書--Python深度學習:邏輯、算法與編程實戰(ISBN:978-7-111-65861-0)。本書可作為深度學習相關從業人員的參考指南,也可作為大中專院校人工智慧相關專業的教材,還可作為廣大人工智慧愛好者的拓展學習手冊。國家「萬人計劃」領軍人才、西安電子科技大學計算智能研究所所長公茂果,浙江宇視科技有限公司研發副總裁/研究院副院長、人工智慧專家周迪聯合推薦。
  • Python中排序算法的重要性,希爾排序 ShellSort,中級python技術
    Python中的Timsort算法,Timsort算法的優缺點,中級python技術點Python中的快速排序算法,快速排序的優缺點,中級python技術點Python中的合併排序算法,合併排序的優缺點,中級python技術點
  • 算法工程師面試問題及資料超詳細合集(多家公司算法崗面經/代碼實戰/網課/競賽等)
    website數據科學&機器學習基礎面試題 website計算機視覺、算法崗實習面經(阿里/格靈深瞳/南京地平線機器人) website面經 | 掛兩次騰訊面試的春招教訓 websiteFace++公司 - 兩輪技術面試面經 website秋招面經 | 曠視科技算法崗秋招面試經驗分享 website面經+經驗分享
  • 史上最全300本Python電子書免費分享
    核心算法與TensorFlow實現(pdf+源碼).zip模式分類 Richard O.Duda 中譯本.pdf面向對象的思考過程.pdf碼農 第8期.pdf碼農 第7期.pdf碼農 第6期.pdf碼農 第5期.pdf流暢的python.pdf零基礎學python.pdf量化投資以Python為工具.pdf利用Python進行數據分析(###).pdf可愛的Python(哲思社區.插圖版_文字版)
  • Python300本電子書免費送
    集體智慧編程-python算法應用.pdf42. 基於Python實現的微信好友數據分析.pdf43. 機器學習在量化投資中的應用研究_湯凌冰著_北京:電子工業出版社_2014.11_13662591_P157.pdf44. 機器學習實戰代碼.zip45. 機器學習實戰.pdf46.
  • SegmentFault 技術周刊 Vol.30 - 學習 Python 來做一些神奇好玩的事情吧
    ,通過這本收可以學到有關對象識別、基於內容的圖像搜索、光學字符識別、光流法、跟蹤、三維重建、立體成像、增強現實、姿態估計、全景創建、圖像分割、降噪、圖像分組等技術的實現原理。相對NumPy,SciPy庫提供了面向更高層應用的算法和函數(其實也是基於NumPy實現的),並以子模塊的形式組織,每個子模塊對應不同的應用領域。邊緣檢測(edge detection)是最重要的圖像處理技術之一,圖像邊緣檢測大幅度地減少了數據量,並且剔除了可以認為不相關的信息,保留了圖像重要的結構屬性,為後續圖像理解方法提供了基礎。