1.5 量化技術(shù)篇—使用zipline回測

------從零開始學(xué)量化------
簡書量化目錄傳送門
知乎量化目錄傳送門


0. 前言

在1.4中夺颤,我們實(shí)現(xiàn)了一個(gè)簡單的量化擇時(shí)策略,那么該策略到底效果如何呢凿渊?我們該使用什么開源框架秤标,使用歷史數(shù)據(jù)回測策略呢揪阶?我們又該用那些指標(biāo)評價(jià)一個(gè)策略遣总?

本篇的內(nèi)容就是回答以上的問題的睬罗,下面給一個(gè)簡要的答案:

回測的開源框架zipline

策略的評價(jià)指標(biāo)

  • 累計(jì)收益
  • 年化收益
  • 最大回撤
  • 夏普比率

為什么選擇zipline轨功?主要由以下幾點(diǎn)原因:

  • 在quant的框架中star數(shù)最多,版本更新和維護(hù)比較快容达。
  • 社區(qū)生態(tài)比較好古涧,出現(xiàn)問題,google容易找到解決方案花盐。
  • 該框架在國外已經(jīng)比較成熟羡滑,坑少。

1. 策略的回測結(jié)果

1.1 策略的回測指標(biāo)

年化收益率 = 8.34%
累計(jì)收益率 = 17.37%
最大回撤 = -16.14%
夏普比率 = 0.62

1.2 策略的收益圖

策略收益圖

1.3 回測的環(huán)境

量化框架:zipline(version = 1.3.0)

1.4 策略追蹤的股票和benchmark

追蹤的股票:個(gè)股選擇了蘋果(AAPL)
benchmark:美國標(biāo)普500(SPX)的指數(shù)
策略時(shí)間: 2015-01-01 ~ 2017-01-01

1.5 擇時(shí)策略描述

買入: 當(dāng)cci >= 50
賣出:當(dāng)cci < 50

2. zipline回測前的準(zhǔn)備

在開始回測之前算芯,zipline首先需要下載數(shù)據(jù)包(data bundle)柒昏。由于在1.2篇——環(huán)境安裝中已經(jīng)說明了zipline的安裝方式,如果還有問題可以查看zipline github installation。下面假設(shè)大家已經(jīng)使用anaconda安裝好了zipline(我的zipline的版本是1.3.0)也祠。

zipline安裝完畢后昙楚,可以打開命令行近速,輸入命令查詢zipline目前支持的數(shù)據(jù)包诈嘿,具體可以參考Zipline Data Bundles,輸入的命令如下:

# 命令行中輸入查詢數(shù)據(jù)包的命令
zipline bundles

# 返回的結(jié)果
csvdir <no ingestions>
quandl <no ingestions>
quantopian-quandl <no ingestions>

從命令行中可以看到削葱,zipline中沒有載入任何數(shù)據(jù)包奖亚。然后我們開始下載數(shù)據(jù)包,具體可以參考Zipline 的安裝配置析砸。下載數(shù)據(jù)包主要分為兩步:

第一步:登錄quandl官網(wǎng)昔字,進(jìn)行注冊,獲得api key首繁。

第二部:設(shè)置api key作郭,并下載數(shù)據(jù)包,具體命令如下:

# 設(shè)置quandl的api key
set QUANDL_API_KEY=your_key

# 下載數(shù)據(jù)包
zipline ingest -b quandl

# 查詢數(shù)據(jù)包
 zipline bundles
# 返回
csvdir <no ingestions>
quandl 2018-07-23 09:34:37.144466
quandl 2018-07-23 09:28:37.817531
quantopian-quandl <no ingestions>

當(dāng)zipline bundles 返回的quandl中出現(xiàn)上面的返回弦疮,說明數(shù)據(jù)下載成功夹攒。

3. 策略代碼

from datetime import datetime

import matplotlib.pyplot as plt
import pytz
import seaborn as sns
import talib as ta
from empyrical import cum_returns, annual_return, sharpe_ratio, max_drawdown
from matplotlib.dates import DateFormatter
from zipline import run_algorithm
from zipline.api import symbol, order, record
from zipline.finance import commission, slippage


def initialize(context):
    # 記錄股票代碼,通過股票代碼獲取股票對象
    context.asset = symbol('AAPL')

    # 定義是否買入股票的標(biāo)記
    context.invested = False

    # 設(shè)置交易的手續(xù)費(fèi)胁塞,股票成交時(shí)咏尝,手續(xù)費(fèi)按成交金額一定比例收取
    # 設(shè)置手續(xù)費(fèi)率和最低費(fèi)用
    context.set_commission(commission.PerShare(cost=.0075, min_trade_cost=1.0))

    # 設(shè)置模擬真實(shí)交易的滑價(jià),當(dāng)實(shí)際下單交易時(shí)啸罢,下單訂單將影響市場编检。買單驅(qū)使價(jià)格上漲,賣單驅(qū)使價(jià)格下滑;
    # 這通常被稱為交易的“價(jià)格影響”扰才。價(jià)格影響的大小取決于訂單與當(dāng)前交易量相比有多大允懂。
    context.set_slippage(slippage.VolumeShareSlippage(volume_limit=0.025, price_impact=0.1))


def handle_data(context, data):
    # 獲取歷史股票數(shù)據(jù)
    # context.asset表示股票列表
    # fields – 歷史數(shù)據(jù)項(xiàng)或集合,項(xiàng)可以為’close’, ‘open’, ‘high’, ‘low’, ‘price’
    # bar_count – 獲取多少單位時(shí)間
    # frequency – 可以取值‘1m’ 或 ‘1d’衩匣。 ‘1m’表示分鐘單位, ‘1d’表示日單位, 現(xiàn)在只支持日單位
    trailing_window = data.history(context.asset, ['high', 'low', 'close', 'open'], 40, '1d')

    # 數(shù)據(jù)為空則返回
    if trailing_window.isnull().values.any():
    return

    # 計(jì)算cci指標(biāo)
    cci = ta.CCI(trailing_window['high'].values, trailing_window['low'].values, trailing_window['close'].values,
    timeperiod=14)

    # 定義買入和賣出的標(biāo)志位
    buy = False
    sell = False

    if (cci[-1] >= 50) and not context.invested:
    # 買賣股票蕾总,按股票數(shù)量生成訂單酣倾,amount為負(fù),表示做空谤专。
    # 參數(shù):
    # asset – 股票
    # amount – 交易數(shù)量, 正數(shù)表示買入, 負(fù)數(shù)表示賣出
    # style –(可選參數(shù))指定下單類型躁锡,默認(rèn)為市價(jià)單,可用的下單類型如下:
    #   style=MarketOrder()置侍,下市價(jià)單
    #   style=StopOrder(stop_price)映之,下止損單,通常用來止損或者鎖定利潤
    #   style=LimitOrder(limit_price)蜡坊,下限價(jià)單杠输,限定一個(gè)價(jià)格買入或賣出
    #   style=StopLimitOrder(limit_price=price1, stop_price=price2),指定限價(jià)和止損價(jià)格
    order(context.asset, 100)
    # 設(shè)置買入
    context.invested = True
    buy = True
    elif (cci[-1] < 50) and context.invested:
    order(context.asset, -100)
    context.invested = False
    sell = True

    # 記錄函數(shù)秕衙,在交易執(zhí)行時(shí)記錄用戶自定義數(shù)據(jù)蠢甲,該數(shù)據(jù)存放在回測輸出結(jié)果中
    record(open=data.current(context.asset, "open"),
        high=data.current(context.asset, "high"),
        low=data.current(context.asset, "low"),
        close=data.current(context.asset, "close"),
        cci=cci[-1],
        buy=buy,
        sell=sell)


# 定義分析回測效果的函數(shù)
def analyze(context=None, results=None):
    pass


def draw_return_rate_line(result):
    sns.set_style('darkgrid')
    sns.set_context('notebook')
    ax = plt.axes()
    # 設(shè)置時(shí)間顯示格式
    years_fmt = DateFormatter('%Y-%m-%d')
    ax.xaxis.set_major_formatter(years_fmt)
    # 讓x軸坐標(biāo)旋轉(zhuǎn)45度
    labels = ax.get_xticklabels()
    plt.setp(labels, rotation=35, horizontalalignment='right')
    # 畫出收益率曲線
    sns.lineplot(x='period_close',
    y='algorithm_period_return',
    data=result,
    label="AAPL")
    sns.lineplot(x='period_close',
        y='benchmark_period_return',
        data=result, label="SPX")

    plt.legend(loc='upper left')
    plt.title("return rate of AAPL and SPX")
    plt.xlabel('time')
    plt.ylabel('return rate')
    plt.show()


if __name__ == '__main__':
    capital_base = 10000
    start = datetime(2015, 1, 1, 0, 0, 0, 0, pytz.utc)
    end = datetime(2017, 1, 1, 0, 0, 0, 0, pytz.utc)

    # 運(yùn)行算法
    result = run_algorithm(start=start, end=end, initialize=initialize,
        capital_base=capital_base, handle_data=handle_data,
        bundle='quandl', analyze=analyze)

    # 畫出收益曲線圖
    draw_return_rate_line(result)

    return_list = result['returns']

    # 計(jì)算年化收益率
    ann_return = annual_return(return_list)

    # 計(jì)算累計(jì)收益率
    cum_return_list = cum_returns(return_list)

    # 計(jì)算sharp ratio
    sharp = sharpe_ratio(return_list)

    # 最大回撤
    max_drawdown_ratio = max_drawdown(return_list)

    print("年化收益率 = {:.2%}, 累計(jì)收益率 = {:.2%}, 最大回撤 = {:.2%}, 夏普比率 = {:.2f} ".format
        (ann_return, cum_return_list[-1], max_drawdown_ratio, sharp))

如果你對我的文章有興趣,可以關(guān)注一下我的簡書和知乎据忘,后期會(huì)在簡書和知乎上定期更新鹦牛,傳送門在下方:
簡書瀟瀟夜雨歸何處
知乎瀟瀟夜雨
我相信,有趣的靈魂總會(huì)相遇S碌酢B贰!
你的關(guān)注汉规,是我前進(jìn)的動(dòng)力@袷狻!针史!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晶伦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子啄枕,更是在濱河造成了極大的恐慌婚陪,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件射亏,死亡現(xiàn)場離奇詭異近忙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)智润,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門及舍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窟绷,你說我怎么就攤上這事锯玛。” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵攘残,是天一觀的道長拙友。 經(jīng)常有香客問我,道長歼郭,這世上最難降的妖魔是什么遗契? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮病曾,結(jié)果婚禮上牍蜂,老公的妹妹穿的比我還像新娘。我一直安慰自己泰涂,他們只是感情好鲫竞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逼蒙,像睡著了一般从绘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上是牢,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天僵井,我揣著相機(jī)與錄音,去河邊找鬼妖泄。 笑死驹沿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蹈胡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼朋蔫,長吁一口氣:“原來是場噩夢啊……” “哼罚渐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起驯妄,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤荷并,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后青扔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體源织,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年微猖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谈息。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凛剥,死狀恐怖侠仇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤逻炊,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布互亮,位于F島的核電站,受9級特大地震影響余素,放射性物質(zhì)發(fā)生泄漏豹休。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一桨吊、第九天 我趴在偏房一處隱蔽的房頂上張望慕爬。 院中可真熱鬧,春花似錦屏积、人聲如沸医窿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姥卢。三九已至,卻和暖如春渣聚,著一層夾襖步出監(jiān)牢的瞬間独榴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工奕枝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棺榔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓隘道,卻偏偏與公主長得像症歇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子谭梗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 31,938評論 2 89
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,170評論 25 707
  • 桃花源里春意濃忘晤,美女仙女還想控,帥哥同喜綠葉靜激捏,還是小兒最盡興设塔。
    書之魂閱讀 159評論 0 0
  • 今天闰蛔,2018年2月1日,再次開啟早起打卡图柏。 為了(爭)第一名序六,昨晚設(shè)置鬧鐘5點(diǎn),計(jì)劃5點(diǎn)開始拍肺經(jīng)和大腸經(jīng)爆办。 然...
    若水柳柳柳閱讀 426評論 0 0
  • 我聽過最常見的擇偶標(biāo)準(zhǔn)难咕,不是“我希望他很有錢”,也不是“我希望他長得好看”,而是“我希望他是個(gè)有趣的人”余佃。 也...
    沈一刀的刀閱讀 800評論 4 15