mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-08 04:00:31 +08:00
59c8e371a2
Adds the data bundle concept which makes it easy for users to register loading functions to build out minute and daily data along with an assets db and adjustments db. By default we have provided a `quandl` bundle which pulls from the public domain WIKI dataset. Users may register new bundles by decorating an ingest function with `zipline.data.bundles.register(<name>)`. This also provides a `yahoo_equities` function for creating an ingestion function that will load a static set of assets from yahoo. The cli is now structured as a couple of subcommands and has been changed to `python -m zipline`. The old behavior of `run_algo.py` has been moved to the `run` subcommand. This is almost entirely the same except that it now takes the name of the data bundle to use, defaulting to `quandl`. The next subcommand is `ingest` which takes the name of a data bundle to ingest. This will run the loading machinery and write the data to a specified location that `run` can find. There is also a `clean` subcommand which deletes the data that was written with `ingest`. Extensions have also been added to zipline. This is an experimental feature where users can provide an extra set of python files to run at the start of the process. These can be used to configure aspects of zipline. Right now the only thing that is supported in an extension file is the registration of a new data bundle.
169 lines
4.6 KiB
Python
169 lines
4.6 KiB
Python
import sys
|
|
import logbook
|
|
import numpy as np
|
|
|
|
from zipline.finance import commission
|
|
|
|
zipline_logging = logbook.NestedSetup([
|
|
logbook.NullHandler(),
|
|
logbook.StreamHandler(sys.stdout, level=logbook.INFO),
|
|
logbook.StreamHandler(sys.stderr, level=logbook.ERROR),
|
|
])
|
|
zipline_logging.push_application()
|
|
|
|
STOCKS = ['AMD', 'CERN', 'COST', 'DELL', 'GPS', 'INTC', 'MMM']
|
|
|
|
|
|
# On-Line Portfolio Moving Average Reversion
|
|
|
|
# More info can be found in the corresponding paper:
|
|
# http://icml.cc/2012/papers/168.pdf
|
|
def initialize(algo, eps=1, window_length=5):
|
|
algo.stocks = STOCKS
|
|
algo.sids = [algo.symbol(symbol) for symbol in algo.stocks]
|
|
algo.m = len(algo.stocks)
|
|
algo.price = {}
|
|
algo.b_t = np.ones(algo.m) / algo.m
|
|
algo.last_desired_port = np.ones(algo.m) / algo.m
|
|
algo.eps = eps
|
|
algo.init = True
|
|
algo.days = 0
|
|
algo.window_length = window_length
|
|
|
|
algo.set_commission(commission.PerShare(cost=0))
|
|
|
|
|
|
def handle_data(algo, data):
|
|
algo.days += 1
|
|
if algo.days < algo.window_length:
|
|
return
|
|
|
|
if algo.init:
|
|
rebalance_portfolio(algo, data, algo.b_t)
|
|
algo.init = False
|
|
return
|
|
|
|
m = algo.m
|
|
|
|
x_tilde = np.zeros(m)
|
|
b = np.zeros(m)
|
|
|
|
# find relative moving average price for each asset
|
|
mavgs = data.history(algo.sids, 'price', algo.window_length, '1d').mean()
|
|
for i, sid in enumerate(algo.sids):
|
|
price = data.current(sid, "price")
|
|
# Relative mean deviation
|
|
x_tilde[i] = mavgs[sid] / price
|
|
|
|
###########################
|
|
# Inside of OLMAR (algo 2)
|
|
x_bar = x_tilde.mean()
|
|
|
|
# market relative deviation
|
|
mark_rel_dev = x_tilde - x_bar
|
|
|
|
# Expected return with current portfolio
|
|
exp_return = np.dot(algo.b_t, x_tilde)
|
|
weight = algo.eps - exp_return
|
|
variability = (np.linalg.norm(mark_rel_dev)) ** 2
|
|
|
|
# test for divide-by-zero case
|
|
if variability == 0.0:
|
|
step_size = 0
|
|
else:
|
|
step_size = max(0, weight / variability)
|
|
|
|
b = algo.b_t + step_size * mark_rel_dev
|
|
b_norm = simplex_projection(b)
|
|
np.testing.assert_almost_equal(b_norm.sum(), 1)
|
|
|
|
rebalance_portfolio(algo, data, b_norm)
|
|
|
|
# update portfolio
|
|
algo.b_t = b_norm
|
|
|
|
|
|
def rebalance_portfolio(algo, data, desired_port):
|
|
# rebalance portfolio
|
|
desired_amount = np.zeros_like(desired_port)
|
|
current_amount = np.zeros_like(desired_port)
|
|
prices = np.zeros_like(desired_port)
|
|
|
|
if algo.init:
|
|
positions_value = algo.portfolio.starting_cash
|
|
else:
|
|
positions_value = algo.portfolio.positions_value + \
|
|
algo.portfolio.cash
|
|
|
|
for i, sid in enumerate(algo.sids):
|
|
current_amount[i] = algo.portfolio.positions[sid].amount
|
|
prices[i] = data.current(sid, "price")
|
|
|
|
desired_amount = np.round(desired_port * positions_value / prices)
|
|
|
|
algo.last_desired_port = desired_port
|
|
diff_amount = desired_amount - current_amount
|
|
|
|
for i, sid in enumerate(algo.sids):
|
|
algo.order(sid, diff_amount[i])
|
|
|
|
|
|
def simplex_projection(v, b=1):
|
|
"""Projection vectors to the simplex domain
|
|
|
|
Implemented according to the paper: Efficient projections onto the
|
|
l1-ball for learning in high dimensions, John Duchi, et al. ICML 2008.
|
|
Implementation Time: 2011 June 17 by Bin@libin AT pmail.ntu.edu.sg
|
|
Optimization Problem: min_{w}\| w - v \|_{2}^{2}
|
|
s.t. sum_{i=1}^{m}=z, w_{i}\geq 0
|
|
|
|
Input: A vector v \in R^{m}, and a scalar z > 0 (default=1)
|
|
Output: Projection vector w
|
|
|
|
:Example:
|
|
>>> proj = simplex_projection([.4 ,.3, -.4, .5])
|
|
>>> print(proj)
|
|
array([ 0.33333333, 0.23333333, 0. , 0.43333333])
|
|
>>> print(proj.sum())
|
|
1.0
|
|
|
|
Original matlab implementation: John Duchi (jduchi@cs.berkeley.edu)
|
|
Python-port: Copyright 2013 by Thomas Wiecki (thomas.wiecki@gmail.com).
|
|
"""
|
|
|
|
v = np.asarray(v)
|
|
p = len(v)
|
|
|
|
# Sort v into u in descending order
|
|
v = (v > 0) * v
|
|
u = np.sort(v)[::-1]
|
|
sv = np.cumsum(u)
|
|
|
|
rho = np.where(u > (sv - b) / np.arange(1, p + 1))[0][-1]
|
|
theta = np.max([0, (sv[rho] - b) / (rho + 1)])
|
|
w = (v - theta)
|
|
w[w < 0] = 0
|
|
return w
|
|
|
|
|
|
# Note: this function can be removed if running
|
|
# this algorithm on quantopian.com
|
|
def analyze(context=None, results=None):
|
|
import matplotlib.pyplot as plt
|
|
fig = plt.figure()
|
|
ax = fig.add_subplot(111)
|
|
results.portfolio_value.plot(ax=ax)
|
|
ax.set_ylabel('Portfolio value (USD)')
|
|
plt.show()
|
|
|
|
|
|
def _test_args():
|
|
"""Extra arguments to use when zipline's automated tests run this example.
|
|
"""
|
|
import pandas as pd
|
|
|
|
return {
|
|
'start': pd.Timestamp('2004', tz='utc'),
|
|
'end': pd.Timestamp('2008', tz='utc'),
|
|
}
|