Přeskočit na hlavní obsah

Tvorba obchodní strategie pomocí Zipline

Existují specializované nástroje přímo zaměřené pro automatické algoritmické obchodování. Jedním z takových je i Zipline. Díky němu se nemusím zabývat vytvářením statistiky, vytvářením backtestu, ručním stahování dat, atd. Zaměřím se pouze na algoritmus strategie, které chci obchodovat, určím jaké trhy chci obchodovat a pak to stačí jen zapnout. Tak proč toho nevyužít?
obr. Logo Zipline (zdroj: zipline.io/)

Zipline

Informace o notebooku

In [1]:
NB_VERSION = 1,0

import sys
import datetime
import pandas as pd

import zipline
%load_ext zipline

print('Verze notebooku:', '.'.join(map(str, NB_VERSION)))
print('Verze pythonu:', '.'.join(map(str, sys.version_info[0:3])))
print('---')
print('Zipline:', zipline.__version__)
print('Pandas:', pd.__version__)
Verze notebooku: 1.0
Verze pythonu: 3.6.2
---
Zipline: 1.1.1
Pandas: 0.18.1

Zipline info

V minulém příspěvku o backtestu, jsem se zabýval jak pomocí pandas provést backtest. Pandas je velmi mocný pomocník při algoritmickém obchodování, ale backtestování pomocí pandas je náchylné na chyby, už jen z toho důvodu, že pandas je zaměřený na analýzu dat obecně. Všechny datové sloupce si tam člověk musí vytvořit a vypočítat pomocí vzorců manuálně. Existují ale i nástroje, které pandas využívají a funkcionalitu zaměřenou na algoritmické obchodování už mají zabudovanou v sobě. Člověk se tak může zaměřit přímo na obchodování (skládání portfolií a logiku vstupů/výstupů). Backtest a jeho výsledky mu pak provede takovýto nástroj. Jedním z takových nástrojů je právě Zipline.
Zipline je open-source knihovna pro python, kterou vyvíjí lidé kolem Quantopianu a jejich komunita. Podporuje jak backtesting, tak i přímo live-trading a Quantopian používá tuto knihovnu jako backend pro jejich notebooky a algoritmy.

Instalace

Instaluje se přes pip - stačí v příkazové řádce spustit příkaz:
pip install zipline
Po instalaci je třeba ještě říct zipline, jaký zdroj dat má použít. To se provede příkazem zipline ingest. Tím se aktivuje defaultní zdroj dat Quandl:
zipline ingest

Funkce initialize a handle_data

Každý algoritmus v zipline využívá dvě funkce:
  • initialize(context), která se volá jako první na začátku spuštění, v parametru context se definují proměnné, které jsou třeba a nemění se s novými daty.
  • handle_data(context, data), volá se pokaždé, když jsou připravená nová data trhu.
Takže v jednoduchosti si do funkce initialize() definuju jaký trh chci obchodovat - jaké data mě zajímají, a popř. určité nastvení, které chci uchovat po celý průběh algoritmu.
Do funkce handle_data() naprogramuju svůj obchodní systém na bázi křížení klouzavých průměrů, jde prakticky o stejnou strategii jako jsem psal v minulém příspěvku.
Nakonec ještě doplním volitelnou funkci analyze(), která se zavolá na konci celého procesu a zobrazí mi výsledky.
In [2]:
%%zipline --start 2008-1-1 --end 2017-3-1

from zipline.api import order_target, record, symbol
import matplotlib.pyplot as plt

def initialize(context):
    context.i = 0
    context.my_smb = 'AAPL'
    context.asset = symbol(context.my_smb)

    context.short_period = 30
    context.long_period = 90
    

def handle_data(context, data):
    # Přeskočím 90 dní, aby se mohl správně vypočítat
    # klouzavý průměr s delší periodou
    context.i += 1
    if context.i < context.long_period:
        return

    short_mavg = data.history(context.asset, 'price', bar_count=context.short_period, frequency="1d").mean()
    long_mavg = data.history(context.asset, 'price', bar_count=context.long_period, frequency="1d").mean()

    # Obchodní logika - nákup 100 akcií v případě překročení klouzavého průměru nahoru
    if short_mavg > long_mavg:
        order_target(context.asset, 100)
    elif short_mavg < long_mavg:
        order_target(context.asset, 0)

    # Pomocí record uložím hodnoty, které můžu zpracovat později
    record(MARKET=data.current(context.asset, 'price'),
           short_mavg=short_mavg,
           long_mavg=long_mavg)
    

def analyze(context, perf):
    fig = plt.figure(figsize=(16,14))
    ax1 = fig.add_subplot(211)
    perf.portfolio_value.plot(ax=ax1)
    ax1.set_ylabel('Hodnota portfolia v $')

    ax2 = fig.add_subplot(212)
    perf['MARKET'].plot(ax=ax2)
    perf[['short_mavg', 'long_mavg']].plot(ax=ax2)

    perf_trans = perf.ix[[t != [] for t in perf.transactions]]
    buys = perf_trans.ix[[t[0]['amount'] > 0 for t in perf_trans.transactions]]
    sells = perf_trans.ix[
        [t[0]['amount'] < 0 for t in perf_trans.transactions]]
    ax2.plot(buys.index, perf.short_mavg.ix[buys.index],
             '^', markersize=10, color='m')
    ax2.plot(sells.index, perf.short_mavg.ix[sells.index],
             'v', markersize=10, color='k')
    ax2.set_ylabel('Vývoj ceny $')
    plt.legend(loc=0)
    plt.show()
Out[2]:
MARKET algo_volatility algorithm_period_return alpha benchmark_period_return benchmark_volatility beta capital_used ending_cash ending_exposure ... short_mavg short_value shorts_count sortino starting_cash starting_exposure starting_value trading_days transactions treasury_period_return
2008-01-02 21:00:00+00:00 NaN NaN 0.000000 NaN -0.008755 NaN NaN 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 1 [] 0.0391
2008-01-03 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.009233 0.092848 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 2 [] 0.0391
2008-01-04 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.033513 0.193737 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 3 [] 0.0388
2008-01-07 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.034334 0.178424 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 4 [] 0.0386
2008-01-08 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.049928 0.163436 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 5 [] 0.0386
2008-01-09 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.039943 0.198227 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 6 [] 0.0382
2008-01-10 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.033650 0.197672 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 7 [] 0.0391
2008-01-11 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.041447 0.183920 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 8 [] 0.0382
2008-01-14 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.033719 0.185841 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 9 [] 0.0381
2008-01-15 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.054989 0.197766 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 10 [] 0.0372
2008-01-16 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.063128 0.188182 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 11 [] 0.0374
2008-01-17 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.087409 0.201623 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 12 [] 0.0366
2008-01-18 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.096779 0.193419 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 13 [] 0.0366
2008-01-22 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.105944 0.186113 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 14 [] 0.0352
2008-01-23 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.084468 0.222003 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 15 [] 0.0351
2008-01-24 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.076739 0.221772 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 16 [] 0.0368
2008-01-25 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.090076 0.217861 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 17 [] 0.0361
2008-01-28 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.075029 0.226799 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 18 [] 0.0361
2008-01-29 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.070447 0.222931 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 19 [] 0.0369
2008-01-30 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.077286 0.217364 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 20 [] 0.0378
2008-01-31 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.060461 0.225337 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 21 [] 0.0367
2008-02-01 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.045346 0.229075 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 22 [] 0.0362
2008-02-04 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.057383 0.226543 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 23 [] 0.0368
2008-02-05 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.082621 0.235145 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 24 [] 0.0361
2008-02-06 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.090008 0.230651 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 25 [] 0.0361
2008-02-07 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.083989 0.228245 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 26 [] 0.0374
2008-02-08 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.089871 0.224020 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 27 [] 0.0364
2008-02-11 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.085220 0.221305 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 28 [] 0.0362
2008-02-12 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.076739 0.220347 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 29 [] 0.0366
2008-02-13 21:00:00+00:00 NaN 0.000000 0.000000 0.000000 -0.067300 0.219709 0.000000 0.0 1.000000e+07 0.0 ... NaN 0 0 NaN 1.000000e+07 0.0 0.0 30 [] 0.0370
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2017-01-18 21:00:00+00:00 119.990 0.000722 0.003604 0.000380 0.550852 0.649698 0.000088 0.0 1.002404e+07 11999.0 ... 116.149333 0 0 0.804067 1.002404e+07 12000.0 12000.0 2278 [] 0.0242
2017-01-19 21:00:00+00:00 119.780 0.000722 0.003602 0.000379 0.545106 0.649557 0.000088 0.0 1.002404e+07 11978.0 ... 116.505000 0 0 0.803422 1.002404e+07 11999.0 11999.0 2279 [] 0.0247
2017-01-20 21:00:00+00:00 120.000 0.000722 0.003604 0.000379 0.550783 0.649415 0.000088 0.0 1.002404e+07 12000.0 ... 116.840000 0 0 0.803736 1.002404e+07 11978.0 11978.0 2280 [] 0.0248
2017-01-23 21:00:00+00:00 120.080 0.000722 0.003605 0.000379 0.546748 0.649273 0.000088 0.0 1.002404e+07 12008.0 ... 117.141667 0 0 0.803737 1.002404e+07 12000.0 12000.0 2281 [] 0.0241
2017-01-24 21:00:00+00:00 119.970 0.000722 0.003604 0.000379 0.556665 0.649134 0.000088 0.0 1.002404e+07 11997.0 ... 117.403333 0 0 0.803316 1.002404e+07 12008.0 12008.0 2282 [] 0.0247
2017-01-25 21:00:00+00:00 121.880 0.000722 0.003623 0.000381 0.570139 0.648997 0.000088 0.0 1.002404e+07 12188.0 ... 117.667667 0 0 0.807387 1.002404e+07 11997.0 11997.0 2283 [] 0.0253
2017-01-26 21:00:00+00:00 121.940 0.000722 0.003623 0.000381 0.568497 0.648855 0.000088 0.0 1.002404e+07 12194.0 ... 117.955667 0 0 0.807343 1.002404e+07 12188.0 12188.0 2284 [] 0.0251
2017-01-27 21:00:00+00:00 121.950 0.000721 0.003623 0.000381 0.566035 0.648713 0.000088 0.0 1.002404e+07 12195.0 ... 118.181000 0 0 0.807189 1.002404e+07 12194.0 12194.0 2285 [] 0.0249
2017-01-30 21:00:00+00:00 121.630 0.000721 0.003620 0.000380 0.556323 0.648576 0.000088 0.0 1.002404e+07 12163.0 ... 118.395667 0 0 0.806299 1.002404e+07 12195.0 12195.0 2286 [] 0.0249
2017-01-31 21:00:00+00:00 121.350 0.000721 0.003617 0.000380 0.556186 0.648434 0.000088 0.0 1.002404e+07 12135.0 ... 118.580000 0 0 0.805500 1.002404e+07 12163.0 12163.0 2287 [] 0.0245
2017-02-01 21:00:00+00:00 128.750 0.000721 0.003691 0.000388 0.556802 0.648292 0.000088 0.0 1.002404e+07 12875.0 ... 119.006000 0 0 0.821757 1.002404e+07 12135.0 12135.0 2288 [] 0.0248
2017-02-02 21:00:00+00:00 128.530 0.000721 0.003689 0.000387 0.557828 0.648150 0.000088 0.0 1.002404e+07 12853.0 ... 119.402333 0 0 0.821088 1.002404e+07 12875.0 12875.0 2289 [] 0.0248
2017-02-03 21:00:00+00:00 129.080 0.000721 0.003695 0.000388 0.568566 0.648012 0.000088 0.0 1.002404e+07 12908.0 ... 119.806667 0 0 0.822130 1.002404e+07 12853.0 12853.0 2290 [] 0.0249
2017-02-06 21:00:00+00:00 130.289 0.000721 0.003707 0.000389 0.565762 0.647871 0.000088 0.0 1.002404e+07 13028.9 ... 120.247633 0 0 0.824633 1.002404e+07 12908.0 12908.0 2291 [] 0.0242
2017-02-07 21:00:00+00:00 131.530 0.000721 0.003719 0.000390 0.565830 0.647730 0.000088 0.0 1.002404e+07 13153.0 ... 120.755633 0 0 0.827207 1.002404e+07 13028.9 13028.9 2292 [] 0.0240
2017-02-08 21:00:00+00:00 132.040 0.000721 0.003724 0.000390 0.567882 0.647588 0.000088 0.0 1.002404e+07 13204.0 ... 121.272967 0 0 0.828158 1.002404e+07 13153.0 13153.0 2293 [] 0.0234
2017-02-09 21:00:00+00:00 132.420 0.000720 0.003728 0.000391 0.577184 0.647449 0.000088 0.0 1.002404e+07 13242.0 ... 121.271700 0 0 0.828820 1.002404e+07 13204.0 13204.0 2294 [] 0.0240
2017-02-10 21:00:00+00:00 132.120 0.000720 0.003725 0.000390 0.583407 0.647309 0.000088 0.0 1.002404e+07 13212.0 ... 121.800500 0 0 0.827972 1.002404e+07 13242.0 13242.0 2295 [] 0.0241
2017-02-13 21:00:00+00:00 133.290 0.000720 0.003737 0.000391 0.592025 0.647170 0.000088 0.0 1.002404e+07 13329.0 ... 122.369300 0 0 0.830385 1.002404e+07 13212.0 13212.0 2296 [] 0.0243
2017-02-14 21:00:00+00:00 135.020 0.000720 0.003754 0.000393 0.598386 0.647030 0.000088 0.0 1.002404e+07 13502.0 ... 123.025967 0 0 0.834039 1.002404e+07 13329.0 13329.0 2297 [] 0.0247
2017-02-15 21:00:00+00:00 135.510 0.000720 0.003759 0.000393 0.606730 0.646890 0.000088 0.0 1.002404e+07 13551.0 ... 123.688000 0 0 0.834943 1.002404e+07 13502.0 13502.0 2298 [] 0.0251
2017-02-16 21:00:00+00:00 135.345 0.000720 0.003757 0.000393 0.605362 0.646750 0.000088 0.0 1.002404e+07 13534.5 ... 124.348867 0 0 0.834395 1.002404e+07 13551.0 13551.0 2299 [] 0.0245
2017-02-17 21:00:00+00:00 135.720 0.000719 0.003761 0.000393 0.607893 0.646609 0.000088 0.0 1.002404e+07 13572.0 ... 125.002633 0 0 0.835044 1.002404e+07 13534.5 13534.5 2300 [] 0.0242
2017-02-21 21:00:00+00:00 136.700 0.000719 0.003771 0.000394 0.617468 0.646471 0.000088 0.0 1.002404e+07 13670.0 ... 125.645933 0 0 0.837033 1.002404e+07 13572.0 13572.0 2301 [] 0.0243
2017-02-22 21:00:00+00:00 137.110 0.000719 0.003775 0.000394 0.616032 0.646331 0.000088 0.0 1.002404e+07 13711.0 ... 126.267067 0 0 0.837758 1.002404e+07 13670.0 13670.0 2302 [] 0.0242
2017-02-23 21:00:00+00:00 136.530 0.000719 0.003769 0.000393 0.617126 0.646190 0.000088 0.0 1.002404e+07 13653.0 ... 126.864867 0 0 0.836286 1.002404e+07 13711.0 13711.0 2303 [] 0.0238
2017-02-24 21:00:00+00:00 136.660 0.000719 0.003771 0.000393 0.619178 0.646050 0.000088 0.0 1.002404e+07 13666.0 ... 127.445767 0 0 0.836393 1.002404e+07 13653.0 13653.0 2304 [] 0.0231
2017-02-27 21:00:00+00:00 136.930 0.000719 0.003773 0.000393 0.621709 0.645910 0.000088 0.0 1.002404e+07 13693.0 ... 128.052267 0 0 0.836808 1.002404e+07 13666.0 13666.0 2305 [] 0.0236
2017-02-28 21:00:00+00:00 136.990 0.000719 0.003774 0.000393 0.617331 0.645771 0.000088 0.0 1.002404e+07 13699.0 ... 128.667733 0 0 0.836760 1.002404e+07 13693.0 13693.0 2306 [] 0.0236
2017-03-01 21:00:00+00:00 139.790 0.000718 0.003802 0.000396 0.639970 0.645645 0.000088 0.0 1.002404e+07 13979.0 ... 129.344667 0 0 0.842770 1.002404e+07 13699.0 13699.0 2307 [] 0.0246
2307 rows × 40 columns

Závěr

Využil jsem vzorový příklad z dokumentace Zipline. Samozřejmě, že backtest není vše, co zipline umí. Je příjemné, že pokud připravím kód pro zipline, tak stačí jen malá úprava a můžu algoritmus nasadit pro živé obchodování (NE, že bych tento konkrétní algoritmus chtěl ve skutečnosti obchodovat!), nebo ho použít jako algoritmus do platformy Quantopian a nechat si zobrazit další výsledky, či ho umístit na fórum Quantopian komunity a podělit se s ním se světem.
Bohužel jsem měl problém s daty z defaultního datového zdroje. Vývoj akcie 'APPL' (někdy od poloviny roku 2014) neodpovídá skutečnosti. Mám neblahé tušení, že to má něco společného se službou Quandl a ukončení poskytování zdarma dostupných dat ze služeb Google Finance či Yahoo finance. Ale na vzorový příklad pro zipline, jako hlavní účel tohoto postu, to nemá vliv a zde se opravou zabývat nebudu.

Komentáře

Okomentovat

Populární příspěvky z tohoto blogu

Jak hodnotit automatické strategie - Sharpeho poměr (Sharpe ratio)

Dnes trošku teorie. Sharpe ratio je číslo, které se používá k hodnocení investice - ukazuje jak dobře si trading strategie nebo jiná investice vedla v minulosti. Do výpočtu zahrnuje riziko a volatilitu. Obecně čím vyšší Sharpe ratio, tím výšší výnos na podstoupené riziko čím vyšší číslo, tím lépe. úrovní vzorec: z How to Calculate Sharpe Ratio: Definition, Formula & Examples

Kde čerpat inspiraci k Data Science a Pythonu?

Uvedu zde několik zdrojů, které jsem shledal velmi zajímavé pro Python a Data Science a Algoritmic trading. Ilustrační obrázek: z Python Data Science Training

Tvorba obchodní strategie - Backtest

Jak si jednoduše otestovat svoji obchodní myšlenku pomocí zdarma dostupných nástrojů? Jde o vzorový příklad jak si backtestovat svoji obchodní strategii, navazuji tak na předchozí příspěvek. Ilustrativní obrázek: Graf vývoje kapitálu pro jednoduchý vzorový automatický obchodní systém z minulého příspěvku. Tvorba obchodní strategie - backtest ¶ Informace o notebooku a modulech ¶ In [4]: NB_VERSION = 1 , 0 import sys import datetime import numpy as np import pandas as pd print ( 'Verze notebooku:' , '.' . join ( map ( str , NB_VERSION ))) print ( 'Verze pythonu:' , '.' . join ( map ( str , sys . version_info [ 0 : 3 ]))) print ( '---' ) import pandas_datareader as pdr import pandas_datareader.data as pdr_web from matplotlib import __version__ as matplotlib_version print ( 'NumPy:' , np . __version__ ) print ( 'Pandas:' , pd . __version__ ) print ( 'pa