- Main package: Zipline
- Python 3.8 or above (currently support up to 3.11)
- Microsoft Windows OS or macOS or Linux
- Other Python dependency packages: Pandas, Numpy, Logbook, Exchange-calendars, etc.
-
We're going to illustrate under anaconda environment, so we suggest using Anaconda as development environment.
-
Download dependency packages.
-
Windows (zipline-tej.yml)
- Start an Anaconda (base) prompt, create an virtual environment and install the appropriate versions of packages: (We strongly recommand using virtual environment to keep every project independent.) (reason)
Windows Users
# change directionary to the folder exists zipline-tej.yml
$ cd <C:\Users\username\Downloads>
# create virtual env
$ conda env create -f zipline-tej.yml
# activate virtual env
$ conda activate zipline-tej
Mac Users
# change directionary to the folder exists zipline-tej_mac.yml
$ cd <C:\Users\username\Downloads>
# create virtual env
$ conda env create -f zipline-tej_mac.yml
# activate virtual env
$ conda activate zipline-tej
Also, if you are familiar with Python enough, you can create a virtual environment without zipline-tej.yml and here's the sample :
# create virtual env
$ conda create -n <env_name> python=3.10
# activate virtual env
$ conda activate <env_name>
# download dependency packages
$ pip install zipline-tej
While encountering environment problems, we provided a consistent and stable environment on Docker hub.
For users that using docker, we briefly introduce how to download and use it.
First of all, please download and install docker-desktop.
1. Start docker-desktop. (Registration is not must.)
2. Select the "images" on the leftside and search "tej87681088/tquant" and click "Pull".
3. After the image was downloaded, click the "run" icon the enter the optional settings.
3-1. Contaner-name: whatever you want.
3-2. Ports: the port to connect, "8888" is recommended.
3-3. Volumes: the place to store files. (You can create volume first on the left side.)
e.g. created a volume named "data", host path enter "data", container path "/app" is recommended.
4. Select the "Containers" leftside, the click the one which its image name is tej87681088/tquant
5. In its "Logs" would show an url like
http://127.0.0.1:8888/tree?token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6. Go to your browser and enter "http://127.0.0.1:<port_you_set_in_step_3-2>/tree?token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
6-1. If your port is 8888, you can just click the hyperlink.
7. Start develop your strategy!
NOTICE: Next time, we just need to reproduce step4 to step6.
The following code implements a simple buy-and-hold trading algorithm.
from zipline.api import order, record, symbol
def initialize(context):
context.asset = symbol("2330")
def handle_data(context, data):
order(context.asset, 10)
record(TSMC=data.current(context.asset, "price"))
def analyze(context=None, results=None):
import matplotlib.pyplot as plt
# Plot the portfolio and asset data.
ax1 = plt.subplot(211)
results.portfolio_value.plot(ax=ax1)
ax1.set_ylabel("Portfolio value (TWD)")
ax2 = plt.subplot(212, sharex=ax1)
results.TSMC.plot(ax=ax2)
ax2.set_ylabel("TSMC price (TWD)")
# Show the plot.
plt.gcf().set_size_inches(18, 8)
plt.show()
You can then run this algorithm using the Zipline CLI. But first, you need to download some market data with historical prices and trading volumes:
- Before ingesting data, you have to set some environment variables as follow:
# setting TEJAPI_KEY to get permissions loading data
$ set TEJAPI_KEY=<your_key>
$ set TEJAPI_BASE=https://api.tej.com.tw
# setting download ticker
$ set ticker=2330 2317
# setting backtest period
$ set mdate=20200101 20220101
- Ingest and run backtesting algorithm
$ zipline ingest -b tquant
$ zipline run -f buy_and_hold.py --start 20200101 --end 20220101 -o bah.pickle --no-benchmark --no-treasury
Then, the resulting performance DataFrame is saved as bah.pickle, which you can load and analyze from Python.
Before calling zipline in CLI, be sure that TEJAPI_KEY and TEJAPI_BASE were set. Use zipline --help to get more information.
For example : We want to know how to use zipline run, we can run as follow:
zipline run --help
Usage: zipline run [OPTIONS]
Run a backtest for the given algorithm.
Options:
-f, --algofile FILENAME The file that contains the algorithm to run.
-t, --algotext TEXT The algorithm script to run.
-D, --define TEXT Define a name to be bound in the namespace
before executing the algotext. For example
'-Dname=value'. The value may be any python
expression. These are evaluated in order so
they may refer to previously defined names.
--data-frequency [daily|minute]
The data frequency of the simulation.
[default: daily]
--capital-base FLOAT The starting capital for the simulation.
[default: 10000000.0]
-b, --bundle BUNDLE-NAME The data bundle to use for the simulation.
[default: tquant]
--bundle-timestamp TIMESTAMP The date to lookup data on or before.
[default: <current-time>]
-bf, --benchmark-file FILE The csv file that contains the benchmark
returns
--benchmark-symbol TEXT The symbol of the instrument to be used as a
benchmark (should exist in the ingested
bundle)
--benchmark-sid INTEGER The sid of the instrument to be used as a
benchmark (should exist in the ingested
bundle)
--no-benchmark If passed, use a benchmark of zero returns.
-bf, --treasury-file FILE The csv file that contains the treasury
returns
--treasury-symbol TEXT The symbol of the instrument to be used as a
treasury (should exist in the ingested
bundle)
--treasury-sid INTEGER The sid of the instrument to be used as a
treasury (should exist in the ingested
bundle)
--no-treasury If passed, use a treasury of zero returns.
-s, --start DATE The start date of the simulation.
-e, --end DATE The end date of the simulation.
-o, --output FILENAME The location to write the perf data. If this
is '-' the perf will be written to stdout.
[default: -]
--trading-calendar TRADING-CALENDAR
The calendar you want to use e.g. TEJ_XTAI.
TEJ_XTAI is the default.
--print-algo / --no-print-algo Print the algorithm to stdout.
--metrics-set TEXT The metrics set to use. New metrics sets may
be registered in your extension.py.
--blotter TEXT The blotter to use. [default: default]
--help Show this message and exit.
-
Basically,
tquant
is the one that only contain OHLCV and cash dividend date. Andfundamentals
is the data that exclude from OHLCV, like EPS, gross margin, operating income, etc. -
So in both fundamentals and tquant, we can add tickers as follow :
$ zipline add -t "<ticker_wants_to_add>"
If tickers are more than 1 ticker, split them apart by " " or "," or ";".
$ zipline add -f "<field_wants_to_add>"
- NOTICE that you
CAN'T
add field and ticker simultaneously.
For more detail use zipline add --help .
$ zipline bundle-info
To show what the tickers are there in newest bundle.
For more detail use zipline bundle-info --help .
Before using switch, use zipline bundles to get the timestamp of each folder.
$ zipline switch -t "<The_timestamp_of_the_folder_want_to_use>"
Due to zipline only using the newest folder, switch can make previous folder become newest.
For more detail use zipline switch --help .
- You can either update
tquant
orfundamentals
by using -b to select which one you want to update the bundle information to newest date.[DEFAULT:tquant]
$ zipline update -b tquant
$ zipline update -b fundamentals
For more detail use zipline update --help .
- Since we've downloaded package "nb_conda_kernels", we should be able to change kernel in jupyter notebook.
(1) Open anaconda prompt
(2) Enter the command as follow :
# First one can be ignore if already in environment of zipline-tej
$ conda activate zipline-tej
# start a jupyter notebook
$ jupyter notebook
(3) Start a notebook and select Python[conda env:zipline-tej]
(4)(Optional) If you have already written a notebook, you can open it and change kernel by clicking the "Kernel" in menu and "Change kernel" to select the specfic kernel.
* ticker would be your target ticker symbol, and it should be a string. If there're more than one ticker needed, use " ", "," or ";" to split them apart.
* mdate refers the begin date and end date, use " ", "," or ";" to split them apart.
In[1]:
import os
os.environ['TEJAPI_KEY'] = <your_key>
os.environ['ticker'] ='2330 2317'
os.environ['mdate'] ='20200101 20220101'
In[2]:
!zipline ingest -b tquant
[Out]:
Merging daily equity files:
[YYYY-MM-DD HH:mm:ss.ssssss] INFO: zipline.data.bundles.core: Ingesting tquant.
In[3]:
from zipline.api import order, record, symbol
def initialize(context):
context.asset = symbol("2330")
def handle_data(context, data):
order(context.asset, 10)
record(TSMC=data.current(context.asset, "price"))
def analyze(context=None, results=None):
import matplotlib.pyplot as plt
# Plot the portfolio and asset data.
ax1 = plt.subplot(211)
results.portfolio_value.plot(ax=ax1)
ax1.set_ylabel("Portfolio value (TWD)")
ax2 = plt.subplot(212, sharex=ax1)
results.TSMC.plot(ax=ax2)
ax2.set_ylabel("TSMC price (TWD)")
# Show the plot.
plt.gcf().set_size_inches(18, 8)
plt.show()
In[4]:
from zipline import run_algorithm
import pandas as pd
from zipline.utils.calendar_utils import get_calendar
trading_calendar = get_calendar('TEJ_XTAI')
start = pd.Timestamp('20200103', tz ='utc' )
end = pd.Timestamp('20211230', tz='utc')
result = run_algorithm(start=start,
end=end,
initialize=initialize,
capital_base=1000000,
handle_data=handle_data,
bundle='tquant',
trading_calendar=trading_calendar,
analyze=analyze,
data_frequency='daily'
)
[Out]:
In[5]:
result
[Out]:
period_open | period_close | starting_value | ending_value | starting_cash | ending_cash | portfolio_value | longs_count | shorts_count | long_value | ... | treasury_period_return | trading_days | period_label | algo_volatility | benchmark_period_return | benchmark_volatility | algorithm_period_return | alpha | beta | sharpe | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2020-01-03 05:30:00+00:00 | 2020-01-03 01:01:00+00:00 | 2020-01-03 05:30:00+00:00 | 0.0 | 0.0 | 1.000000e+06 | 1.000000e+06 | 1.000000e+06 | 0 | 0 | 0.0 | ... | 0.0 | 1 | 2020-01 | NaN | 0.0 | NaN | 0.000000 | None | None | NaN |
2020-01-06 05:30:00+00:00 | 2020-01-06 01:01:00+00:00 | 2020-01-06 05:30:00+00:00 | 0.0 | 3320.0 | 1.000000e+06 | 9.966783e+05 | 9.999983e+05 | 1 | 0 | 3320.0 | ... | 0.0 | 2 | 2020-01 | 0.000019 | 0.0 | 0.0 | -0.000002 | None | None | -11.224972 |
2020-01-07 05:30:00+00:00 | 2020-01-07 01:01:00+00:00 | 2020-01-07 05:30:00+00:00 | 3320.0 | 6590.0 | 9.966783e+05 | 9.933817e+05 | 9.999717e+05 | 1 | 0 | 6590.0 | ... | 0.0 | 3 | 2020-01 | 0.000237 | 0.0 | 0.0 | -0.000028 | None | None | -10.038514 |
2020-01-08 05:30:00+00:00 | 2020-01-08 01:01:00+00:00 | 2020-01-08 05:30:00+00:00 | 6590.0 | 9885.0 | 9.933817e+05 | 9.900850e+05 | 9.999700e+05 | 1 | 0 | 9885.0 | ... | 0.0 | 4 | 2020-01 | 0.000203 | 0.0 | 0.0 | -0.000030 | None | None | -9.298128 |
2020-01-09 05:30:00+00:00 | 2020-01-09 01:01:00+00:00 | 2020-01-09 05:30:00+00:00 | 9885.0 | 13500.0 | 9.900850e+05 | 9.867083e+05 | 1.000208e+06 | 1 | 0 | 13500.0 | ... | 0.0 | 5 | 2020-01 | 0.001754 | 0.0 | 0.0 | 0.000208 | None | None | 5.986418 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2021-12-24 05:30:00+00:00 | 2021-12-24 01:01:00+00:00 | 2021-12-24 05:30:00+00:00 | 2920920.0 | 2917320.0 | -1.308854e+06 | -1.314897e+06 | 1.602423e+06 | 1 | 0 | 2917320.0 | ... | 0.0 | 484 | 2021-12 | 0.232791 | 0.0 | 0.0 | 0.602423 | None | None | 1.170743 |
2021-12-27 05:30:00+00:00 | 2021-12-27 01:01:00+00:00 | 2021-12-27 05:30:00+00:00 | 2917320.0 | 2933040.0 | -1.314897e+06 | -1.320960e+06 | 1.612080e+06 | 1 | 0 | 2933040.0 | ... | 0.0 | 485 | 2021-12 | 0.232577 | 0.0 | 0.0 | 0.612080 | None | None | 1.182864 |
2021-12-28 05:30:00+00:00 | 2021-12-28 01:01:00+00:00 | 2021-12-28 05:30:00+00:00 | 2933040.0 | 2982750.0 | -1.320960e+06 | -1.327113e+06 | 1.655637e+06 | 1 | 0 | 2982750.0 | ... | 0.0 | 486 | 2021-12 | 0.233086 | 0.0 | 0.0 | 0.655637 | None | None | 1.237958 |
2021-12-29 05:30:00+00:00 | 2021-12-29 01:01:00+00:00 | 2021-12-29 05:30:00+00:00 | 2982750.0 | 2993760.0 | -1.327113e+06 | -1.333276e+06 | 1.660484e+06 | 1 | 0 | 2993760.0 | ... | 0.0 | 487 | 2021-12 | 0.232850 | 0.0 | 0.0 | 0.660484 | None | None | 1.243176 |
2021-12-30 05:30:00+00:00 | 2021-12-30 01:01:00+00:00 | 2021-12-30 05:30:00+00:00 | 2993760.0 | 2995050.0 | -1.333276e+06 | -1.339430e+06 | 1.655620e+06 | 1 | 0 | 2995050.0 | ... | 0.0 | 488 | 2021-12 | 0.232629 | 0.0 | 0.0 | 0.655620 | None | None | 1.235305 |
488 rows × 38 columns
- For more tutorials
- To get TEJAPI_KEY (link)
- TEJ Official Website