mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-22 12:40:30 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49b6792399 | ||
|
|
6b1982274e | ||
|
|
bc58640a3a | ||
|
|
511af7946e | ||
|
|
dcdb3d9d7a | ||
|
|
5c77cfc68d | ||
|
|
11f8e36ff0 | ||
|
|
44e4e66f5c | ||
|
|
3c4c6c3dfd | ||
|
|
bebebc46dc | ||
|
|
403d7f9c29 | ||
|
|
09ad397ee6 | ||
|
|
e56e1f8e21 | ||
|
|
00f232e2d7 | ||
|
|
a820f66bdc | ||
|
|
82d318a1c0 | ||
|
|
97afbf781e | ||
|
|
43a5f8858b | ||
|
|
dc04cd8781 |
+1
-3
@@ -17,9 +17,7 @@ insights regarding a particular strategy's performance. Catalyst also supports
|
|||||||
live-trading of crypto-assets starting with three exchanges (Bitfinex, Bittrex,
|
live-trading of crypto-assets starting with three exchanges (Bitfinex, Bittrex,
|
||||||
and Poloniex) with more being added over time. Catalyst empowers users to share
|
and Poloniex) with more being added over time. Catalyst empowers users to share
|
||||||
and curate data and build profitable, data-driven investment strategies. Please
|
and curate data and build profitable, data-driven investment strategies. Please
|
||||||
visit `enigma.co <https://www.enigma.co>`_ to learn more about Catalyst, or
|
visit `enigma.co <https://www.enigma.co>`_ to learn more about Catalyst.
|
||||||
refer to the `whitepaper <https://www.enigma.co/enigma_catalyst.pdf>`_ for
|
|
||||||
further technical details.
|
|
||||||
|
|
||||||
Catalyst builds on top of the well-established
|
Catalyst builds on top of the well-established
|
||||||
`Zipline <https://github.com/quantopian/zipline>`_ project. We did our best to
|
`Zipline <https://github.com/quantopian/zipline>`_ project. We did our best to
|
||||||
|
|||||||
@@ -939,7 +939,7 @@ class TradingAlgorithm(object):
|
|||||||
The field to query. The options have the following meanings:
|
The field to query. The options have the following meanings:
|
||||||
arena : str
|
arena : str
|
||||||
The arena from the simulation parameters. This will normally
|
The arena from the simulation parameters. This will normally
|
||||||
be ``'backtest'`` but some systems may use this distinguish
|
be ``backtest`` but some systems may use this distinguish
|
||||||
live trading from backtesting.
|
live trading from backtesting.
|
||||||
data_frequency : {'daily', 'minute'}
|
data_frequency : {'daily', 'minute'}
|
||||||
data_frequency tells the algorithm if it is running with
|
data_frequency tells the algorithm if it is running with
|
||||||
@@ -954,7 +954,7 @@ class TradingAlgorithm(object):
|
|||||||
The platform that the code is running on. By default this
|
The platform that the code is running on. By default this
|
||||||
will be the string 'catalyst'. This can allow algorithms to
|
will be the string 'catalyst'. This can allow algorithms to
|
||||||
know if they are running on the Quantopian platform instead.
|
know if they are running on the Quantopian platform instead.
|
||||||
* : dict[str -> any]
|
\* : dict[str -> any]
|
||||||
Returns all of the fields in a dictionary.
|
Returns all of the fields in a dictionary.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@@ -1032,7 +1032,7 @@ class TradingAlgorithm(object):
|
|||||||
argument is the name of the column in the preprocessed dataframe
|
argument is the name of the column in the preprocessed dataframe
|
||||||
containing the symbols. This will be used along with the date
|
containing the symbols. This will be used along with the date
|
||||||
information to map the sids in the asset finder.
|
information to map the sids in the asset finder.
|
||||||
**kwargs
|
\*\*kwargs
|
||||||
Forwarded to :func:`pandas.read_csv`.
|
Forwarded to :func:`pandas.read_csv`.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@@ -1156,7 +1156,7 @@ class TradingAlgorithm(object):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
**kwargs
|
\*\*kwargs
|
||||||
The names and values to record.
|
The names and values to record.
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
@@ -1273,7 +1273,7 @@ class TradingAlgorithm(object):
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
*args : iterable[str]
|
\*args : iterable[str]
|
||||||
The ticker symbols to lookup.
|
The ticker symbols to lookup.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def _handle_data(context, data):
|
|||||||
rsi=rsi,
|
rsi=rsi,
|
||||||
)
|
)
|
||||||
|
|
||||||
orders = get_open_orders(context.asset)
|
orders = context.blotter.open_orders
|
||||||
if orders:
|
if orders:
|
||||||
log.info('skipping bar until all open orders execute')
|
log.info('skipping bar until all open orders execute')
|
||||||
return
|
return
|
||||||
@@ -146,11 +146,11 @@ if __name__ == '__main__':
|
|||||||
live = True
|
live = True
|
||||||
if live:
|
if live:
|
||||||
run_algorithm(
|
run_algorithm(
|
||||||
capital_base=0.001,
|
capital_base=1000,
|
||||||
initialize=initialize,
|
initialize=initialize,
|
||||||
handle_data=handle_data,
|
handle_data=handle_data,
|
||||||
analyze=analyze,
|
analyze=analyze,
|
||||||
exchange_name='binance',
|
exchange_name='bittrex',
|
||||||
live=True,
|
live=True,
|
||||||
algo_namespace=algo_namespace,
|
algo_namespace=algo_namespace,
|
||||||
base_currency='btc',
|
base_currency='btc',
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ def initialize(context):
|
|||||||
|
|
||||||
def handle_data(context, data):
|
def handle_data(context, data):
|
||||||
# define the windows for the moving averages
|
# define the windows for the moving averages
|
||||||
short_window = 50
|
short_window = 2
|
||||||
long_window = 200
|
long_window = 2
|
||||||
|
|
||||||
# Skip as many bars as long_window to properly compute the average
|
# Skip as many bars as long_window to properly compute the average
|
||||||
context.i += 1
|
context.i += 1
|
||||||
@@ -32,16 +32,18 @@ def handle_data(context, data):
|
|||||||
# moving average with the appropriate parameters. We choose to use
|
# moving average with the appropriate parameters. We choose to use
|
||||||
# minute bars for this simulation -> freq="1m"
|
# minute bars for this simulation -> freq="1m"
|
||||||
# Returns a pandas dataframe.
|
# Returns a pandas dataframe.
|
||||||
short_mavg = data.history(context.asset,
|
short_data = data.history(context.asset,
|
||||||
'price',
|
'price',
|
||||||
bar_count=short_window,
|
bar_count=short_window,
|
||||||
frequency="1m",
|
frequency="1T",
|
||||||
).mean()
|
)
|
||||||
long_mavg = data.history(context.asset,
|
short_mavg = short_data.mean()
|
||||||
|
long_data = data.history(context.asset,
|
||||||
'price',
|
'price',
|
||||||
bar_count=long_window,
|
bar_count=long_window,
|
||||||
frequency="1m",
|
frequency="1T",
|
||||||
).mean()
|
)
|
||||||
|
long_mavg = long_data.mean()
|
||||||
|
|
||||||
# Let's keep the price of our asset in a more handy variable
|
# Let's keep the price of our asset in a more handy variable
|
||||||
price = data.current(context.asset, 'price')
|
price = data.current(context.asset, 'price')
|
||||||
@@ -82,7 +84,6 @@ def handle_data(context, data):
|
|||||||
|
|
||||||
|
|
||||||
def analyze(context, perf):
|
def analyze(context, perf):
|
||||||
|
|
||||||
# Get the base_currency that was passed as a parameter to the simulation
|
# Get the base_currency that was passed as a parameter to the simulation
|
||||||
exchange = list(context.exchanges.values())[0]
|
exchange = list(context.exchanges.values())[0]
|
||||||
base_currency = exchange.base_currency.upper()
|
base_currency = exchange.base_currency.upper()
|
||||||
@@ -93,7 +94,7 @@ def analyze(context, perf):
|
|||||||
ax1.legend_.remove()
|
ax1.legend_.remove()
|
||||||
ax1.set_ylabel('Portfolio Value\n({})'.format(base_currency))
|
ax1.set_ylabel('Portfolio Value\n({})'.format(base_currency))
|
||||||
start, end = ax1.get_ylim()
|
start, end = ax1.get_ylim()
|
||||||
ax1.yaxis.set_ticks(np.arange(start, end, (end-start)/5))
|
ax1.yaxis.set_ticks(np.arange(start, end, (end - start) / 5))
|
||||||
|
|
||||||
# Second chart: Plot asset price, moving averages and buys/sells
|
# Second chart: Plot asset price, moving averages and buys/sells
|
||||||
ax2 = plt.subplot(412, sharex=ax1)
|
ax2 = plt.subplot(412, sharex=ax1)
|
||||||
@@ -104,9 +105,9 @@ def analyze(context, perf):
|
|||||||
ax2.set_ylabel('{asset}\n({base})'.format(
|
ax2.set_ylabel('{asset}\n({base})'.format(
|
||||||
asset=context.asset.symbol,
|
asset=context.asset.symbol,
|
||||||
base=base_currency
|
base=base_currency
|
||||||
))
|
))
|
||||||
start, end = ax2.get_ylim()
|
start, end = ax2.get_ylim()
|
||||||
ax2.yaxis.set_ticks(np.arange(start, end, (end-start)/5))
|
ax2.yaxis.set_ticks(np.arange(start, end, (end - start) / 5))
|
||||||
|
|
||||||
transaction_df = extract_transactions(perf)
|
transaction_df = extract_transactions(perf)
|
||||||
if not transaction_df.empty:
|
if not transaction_df.empty:
|
||||||
@@ -136,28 +137,40 @@ def analyze(context, perf):
|
|||||||
ax3.legend_.remove()
|
ax3.legend_.remove()
|
||||||
ax3.set_ylabel('Percent Change')
|
ax3.set_ylabel('Percent Change')
|
||||||
start, end = ax3.get_ylim()
|
start, end = ax3.get_ylim()
|
||||||
ax3.yaxis.set_ticks(np.arange(start, end, (end-start)/5))
|
ax3.yaxis.set_ticks(np.arange(start, end, (end - start) / 5))
|
||||||
|
|
||||||
# Fourth chart: Plot our cash
|
# Fourth chart: Plot our cash
|
||||||
ax4 = plt.subplot(414, sharex=ax1)
|
ax4 = plt.subplot(414, sharex=ax1)
|
||||||
perf.cash.plot(ax=ax4)
|
perf.cash.plot(ax=ax4)
|
||||||
ax4.set_ylabel('Cash\n({})'.format(base_currency))
|
ax4.set_ylabel('Cash\n({})'.format(base_currency))
|
||||||
start, end = ax4.get_ylim()
|
start, end = ax4.get_ylim()
|
||||||
ax4.yaxis.set_ticks(np.arange(0, end, end/5))
|
ax4.yaxis.set_ticks(np.arange(0, end, end / 5))
|
||||||
|
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
run_algorithm(
|
run_algorithm(
|
||||||
capital_base=1000,
|
capital_base=1000,
|
||||||
data_frequency='minute',
|
data_frequency='minute',
|
||||||
initialize=initialize,
|
initialize=initialize,
|
||||||
handle_data=handle_data,
|
handle_data=handle_data,
|
||||||
analyze=analyze,
|
analyze=analyze,
|
||||||
exchange_name='bitfinex',
|
exchange_name='bitfinex',
|
||||||
algo_namespace=NAMESPACE,
|
algo_namespace=NAMESPACE,
|
||||||
base_currency='usd',
|
base_currency='usd',
|
||||||
start=pd.to_datetime('2017-9-22', utc=True),
|
simulate_orders=True,
|
||||||
end=pd.to_datetime('2017-9-23', utc=True),
|
live=True,
|
||||||
)
|
)
|
||||||
|
# run_algorithm(
|
||||||
|
# capital_base=1000,
|
||||||
|
# data_frequency='minute',
|
||||||
|
# initialize=initialize,
|
||||||
|
# handle_data=handle_data,
|
||||||
|
# analyze=analyze,
|
||||||
|
# exchange_name='bitfinex',
|
||||||
|
# algo_namespace=NAMESPACE,
|
||||||
|
# base_currency='usd',
|
||||||
|
# start=pd.to_datetime('2017-9-22', utc=True),
|
||||||
|
# end=pd.to_datetime('2017-9-23', utc=True),
|
||||||
|
# )
|
||||||
|
|||||||
@@ -425,15 +425,12 @@ class CCXT(Exchange):
|
|||||||
'Please provide either start_dt or end_dt, not both.'
|
'Please provide either start_dt or end_dt, not both.'
|
||||||
)
|
)
|
||||||
|
|
||||||
elif end_dt is not None:
|
if start_dt is None:
|
||||||
# Make sure that end_dt really wants data in the past
|
# TODO: determine why binance is failing
|
||||||
# if it's close to now, we skip the 'since' parameters to
|
if end_dt is None and self.name not in ['binance']:
|
||||||
# lower the probability of error
|
end_dt = pd.Timestamp.utcnow()
|
||||||
bars_to_now = pd.date_range(
|
|
||||||
end_dt, pd.Timestamp.utcnow(), freq=freq
|
if end_dt is not None:
|
||||||
)
|
|
||||||
# See: https://github.com/ccxt/ccxt/issues/1360
|
|
||||||
if len(bars_to_now) > 1 or self.name in ['poloniex']:
|
|
||||||
dt_range = get_periods_range(
|
dt_range = get_periods_range(
|
||||||
end_dt=end_dt,
|
end_dt=end_dt,
|
||||||
periods=bar_count,
|
periods=bar_count,
|
||||||
@@ -441,10 +438,13 @@ class CCXT(Exchange):
|
|||||||
)
|
)
|
||||||
start_dt = dt_range[0]
|
start_dt = dt_range[0]
|
||||||
|
|
||||||
since = None
|
|
||||||
if start_dt is not None:
|
if start_dt is not None:
|
||||||
|
# Convert out start date to a UNIX timestamp, then translate to
|
||||||
|
# milliseconds
|
||||||
delta = start_dt - get_epoch()
|
delta = start_dt - get_epoch()
|
||||||
since = int(delta.total_seconds()) * 1000
|
since = int(delta.total_seconds()) * 1000
|
||||||
|
else:
|
||||||
|
since = None
|
||||||
|
|
||||||
candles = dict()
|
candles = dict()
|
||||||
for index, asset in enumerate(assets):
|
for index, asset in enumerate(assets):
|
||||||
|
|||||||
@@ -391,8 +391,6 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
log.warn("Can't initialize signal handler inside another thread."
|
log.warn("Can't initialize signal handler inside another thread."
|
||||||
"Exit should be handled by the user.")
|
"Exit should be handled by the user.")
|
||||||
|
|
||||||
log.info('initialized trading algorithm in live mode')
|
|
||||||
|
|
||||||
def interrupt_algorithm(self):
|
def interrupt_algorithm(self):
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
|
|
||||||
@@ -874,6 +872,13 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def _get_open_orders(self, asset=None):
|
def _get_open_orders(self, asset=None):
|
||||||
|
if self.simulate_orders:
|
||||||
|
raise ValueError(
|
||||||
|
'The get_open_orders() method only works in live mode. '
|
||||||
|
'The purpose is to list open orders on the exchange '
|
||||||
|
'regardless who placed them. To list the open orders of '
|
||||||
|
'this algo, use `context.blotter.open_orders`.'
|
||||||
|
)
|
||||||
if asset:
|
if asset:
|
||||||
exchange = self.exchanges[asset.exchange]
|
exchange = self.exchanges[asset.exchange]
|
||||||
return exchange.get_open_orders(asset)
|
return exchange.get_open_orders(asset)
|
||||||
@@ -907,6 +912,7 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
If an asset is passed then this will return a list of the open
|
If an asset is passed then this will return a list of the open
|
||||||
orders for this asset.
|
orders for this asset.
|
||||||
"""
|
"""
|
||||||
|
# TODO: should this be a shortcut to the open orders in the blotter?
|
||||||
return retry(
|
return retry(
|
||||||
action=self._get_open_orders,
|
action=self._get_open_orders,
|
||||||
attempts=self.attempts['get_open_orders_attempts'],
|
attempts=self.attempts['get_open_orders_attempts'],
|
||||||
|
|||||||
@@ -458,7 +458,7 @@ class ExchangeBundle:
|
|||||||
last_entry = None
|
last_entry = None
|
||||||
|
|
||||||
if start is None or \
|
if start is None or \
|
||||||
(earliest_trade is not None and earliest_trade > start):
|
(earliest_trade is not None and earliest_trade > start):
|
||||||
start = earliest_trade
|
start = earliest_trade
|
||||||
|
|
||||||
if last_entry is not None and (end is None or end > last_entry):
|
if last_entry is not None and (end is None or end > last_entry):
|
||||||
@@ -600,14 +600,14 @@ class ExchangeBundle:
|
|||||||
if show_breakdown:
|
if show_breakdown:
|
||||||
for asset in chunks:
|
for asset in chunks:
|
||||||
with maybe_show_progress(
|
with maybe_show_progress(
|
||||||
chunks[asset],
|
chunks[asset],
|
||||||
show_progress,
|
show_progress,
|
||||||
label='Ingesting {frequency} price data for '
|
label='Ingesting {frequency} price data for '
|
||||||
'{symbol} on {exchange}'.format(
|
'{symbol} on {exchange}'.format(
|
||||||
exchange=self.exchange_name,
|
exchange=self.exchange_name,
|
||||||
frequency=data_frequency,
|
frequency=data_frequency,
|
||||||
symbol=asset.symbol
|
symbol=asset.symbol
|
||||||
)) as it:
|
)) as it:
|
||||||
for chunk in it:
|
for chunk in it:
|
||||||
problems += self.ingest_ctable(
|
problems += self.ingest_ctable(
|
||||||
asset=chunk['asset'],
|
asset=chunk['asset'],
|
||||||
@@ -625,13 +625,13 @@ class ExchangeBundle:
|
|||||||
key=lambda chunk: pd.to_datetime(chunk['period'])
|
key=lambda chunk: pd.to_datetime(chunk['period'])
|
||||||
)
|
)
|
||||||
with maybe_show_progress(
|
with maybe_show_progress(
|
||||||
all_chunks,
|
all_chunks,
|
||||||
show_progress,
|
show_progress,
|
||||||
label='Ingesting {frequency} price data on '
|
label='Ingesting {frequency} price data on '
|
||||||
'{exchange}'.format(
|
'{exchange}'.format(
|
||||||
exchange=self.exchange_name,
|
exchange=self.exchange_name,
|
||||||
frequency=data_frequency,
|
frequency=data_frequency,
|
||||||
)) as it:
|
)) as it:
|
||||||
for chunk in it:
|
for chunk in it:
|
||||||
problems += self.ingest_ctable(
|
problems += self.ingest_ctable(
|
||||||
asset=chunk['asset'],
|
asset=chunk['asset'],
|
||||||
@@ -830,7 +830,6 @@ class ExchangeBundle:
|
|||||||
field,
|
field,
|
||||||
data_frequency,
|
data_frequency,
|
||||||
algo_end_dt=None,
|
algo_end_dt=None,
|
||||||
trailing_bar_count=None,
|
|
||||||
force_auto_ingest=False
|
force_auto_ingest=False
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -858,7 +857,6 @@ class ExchangeBundle:
|
|||||||
bar_count=bar_count,
|
bar_count=bar_count,
|
||||||
field=field,
|
field=field,
|
||||||
data_frequency=data_frequency,
|
data_frequency=data_frequency,
|
||||||
trailing_bar_count=trailing_bar_count,
|
|
||||||
)
|
)
|
||||||
return pd.DataFrame(series)
|
return pd.DataFrame(series)
|
||||||
|
|
||||||
@@ -887,7 +885,6 @@ class ExchangeBundle:
|
|||||||
field=field,
|
field=field,
|
||||||
data_frequency=data_frequency,
|
data_frequency=data_frequency,
|
||||||
reset_reader=True,
|
reset_reader=True,
|
||||||
trailing_bar_count=trailing_bar_count,
|
|
||||||
)
|
)
|
||||||
return series
|
return series
|
||||||
|
|
||||||
@@ -898,7 +895,6 @@ class ExchangeBundle:
|
|||||||
bar_count=bar_count,
|
bar_count=bar_count,
|
||||||
field=field,
|
field=field,
|
||||||
data_frequency=data_frequency,
|
data_frequency=data_frequency,
|
||||||
trailing_bar_count=trailing_bar_count,
|
|
||||||
)
|
)
|
||||||
return pd.DataFrame(series)
|
return pd.DataFrame(series)
|
||||||
|
|
||||||
@@ -962,12 +958,7 @@ class ExchangeBundle:
|
|||||||
bar_count,
|
bar_count,
|
||||||
field,
|
field,
|
||||||
data_frequency,
|
data_frequency,
|
||||||
trailing_bar_count=None,
|
|
||||||
reset_reader=False):
|
reset_reader=False):
|
||||||
if trailing_bar_count:
|
|
||||||
delta = get_delta(trailing_bar_count, data_frequency)
|
|
||||||
end_dt += delta
|
|
||||||
|
|
||||||
start_dt = get_start_dt(end_dt, bar_count, data_frequency, False)
|
start_dt = get_start_dt(end_dt, bar_count, data_frequency, False)
|
||||||
start_dt, _ = self.get_adj_dates(
|
start_dt, _ = self.get_adj_dates(
|
||||||
start_dt, end_dt, assets, data_frequency
|
start_dt, end_dt, assets, data_frequency
|
||||||
|
|||||||
@@ -298,7 +298,6 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase):
|
|||||||
frequency, data_frequency
|
frequency, data_frequency
|
||||||
)
|
)
|
||||||
adj_bar_count = candle_size * bar_count
|
adj_bar_count = candle_size * bar_count
|
||||||
trailing_bar_count = candle_size - 1
|
|
||||||
|
|
||||||
if data_frequency == 'minute' and adj_data_frequency == 'daily':
|
if data_frequency == 'minute' and adj_data_frequency == 'daily':
|
||||||
end_dt = end_dt.floor('1D')
|
end_dt = end_dt.floor('1D')
|
||||||
@@ -310,7 +309,6 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase):
|
|||||||
field=field,
|
field=field,
|
||||||
data_frequency=adj_data_frequency,
|
data_frequency=adj_data_frequency,
|
||||||
algo_end_dt=self._last_available_session,
|
algo_end_dt=self._last_available_session,
|
||||||
trailing_bar_count=trailing_bar_count,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
df = resample_history_df(pd.DataFrame(series), freq, field)
|
df = resample_history_df(pd.DataFrame(series), freq, field)
|
||||||
|
|||||||
@@ -540,7 +540,7 @@ def resample_history_df(df, freq, field):
|
|||||||
else:
|
else:
|
||||||
raise ValueError('Invalid field.')
|
raise ValueError('Invalid field.')
|
||||||
|
|
||||||
resampled_df = df.resample(freq).agg(agg)
|
resampled_df = df.resample(freq, closed='left', label='left').agg(agg)
|
||||||
return resampled_df
|
return resampled_df
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,376 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# !/usr/bin/env python2
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import pandas as pd
|
||||||
|
import signal
|
||||||
|
# import talib
|
||||||
|
|
||||||
|
from logbook import Logger
|
||||||
|
|
||||||
|
from catalyst import run_algorithm
|
||||||
|
from catalyst.api import (
|
||||||
|
symbol,
|
||||||
|
record,
|
||||||
|
order,
|
||||||
|
order_target,
|
||||||
|
order_target_percent,
|
||||||
|
get_open_orders
|
||||||
|
)
|
||||||
|
from catalyst.finance import commission
|
||||||
|
|
||||||
|
|
||||||
|
# from base.telegrambot import TelegramBot
|
||||||
|
|
||||||
|
|
||||||
|
class GracefulKiller:
|
||||||
|
# Source: https://stackoverflow.com/a/31464349
|
||||||
|
def __init__(self, context):
|
||||||
|
self.kill_now = False
|
||||||
|
self.signal = 0
|
||||||
|
self.context = context
|
||||||
|
signal.signal(signal.SIGINT, self.exit_gracefully)
|
||||||
|
|
||||||
|
def exit_gracefully(self, signum, frame):
|
||||||
|
self.kill_now = True
|
||||||
|
self.signal = signum
|
||||||
|
if hasattr(self.context,
|
||||||
|
'telegram_bot') and self.context.telegram_bot is not None:
|
||||||
|
self.context.telegram_bot.updater.stop()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
return self.kill_now
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationParameters:
|
||||||
|
MODE = 'paper'
|
||||||
|
CAPITAL_BASE = 1000
|
||||||
|
"""
|
||||||
|
Capital base used on this simulation
|
||||||
|
"""
|
||||||
|
|
||||||
|
DATA_FREQUECY = 'minute'
|
||||||
|
|
||||||
|
EXCHANGE_NAME = 'bitfinex'
|
||||||
|
# EXCHANGE_NAME = 'binance'
|
||||||
|
"""
|
||||||
|
Exchange used on this simulation
|
||||||
|
"""
|
||||||
|
|
||||||
|
DATA_DIR = '/home/av/Dropbox/simulations/data'
|
||||||
|
ALGO_NAMESPACE = os.path.basename(__file__).split('.')[0]
|
||||||
|
ALGO_NAMESPACE_IMAGE = '{}/{}/{}.png'.format(DATA_DIR, 'images',
|
||||||
|
ALGO_NAMESPACE)
|
||||||
|
ALGO_NAMESPACE_RESULTS_TABLE = '{}/{}/{}.csv'.format(DATA_DIR, 'tables',
|
||||||
|
ALGO_NAMESPACE + '_results')
|
||||||
|
ALGO_NAMESPACE_TRANSACTIONS_TABLE = '{}/{}/{}.csv'.format(DATA_DIR,
|
||||||
|
'tables',
|
||||||
|
ALGO_NAMESPACE + '_transactions')
|
||||||
|
BASE_CURRENCY = 'usd'
|
||||||
|
# BASE_CURRENCY = 'usdt'
|
||||||
|
|
||||||
|
# SHORT PERIOD
|
||||||
|
START_DATE = '2017-09-07'
|
||||||
|
"""
|
||||||
|
Start date used on this simulation
|
||||||
|
"""
|
||||||
|
END_DATE = '2017-12-12'
|
||||||
|
"""
|
||||||
|
End date used on this simulation
|
||||||
|
"""
|
||||||
|
|
||||||
|
SKIP_FIRST_CANDLES = 0
|
||||||
|
|
||||||
|
# CANDLES_SAMPLE_RATE = 60
|
||||||
|
# CANDLES_SAMPLE_RATE = 30
|
||||||
|
CANDLES_SAMPLE_RATE = 1
|
||||||
|
"""
|
||||||
|
Candle interval used on this simulation (in minutes)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
|
||||||
|
# 30 minute interval ohlcv data (the standard data required for candlestick or
|
||||||
|
# indicators/signals)
|
||||||
|
# 30T means 30 minutes re-sampling of one minute data.
|
||||||
|
# CANDLES_FREQUENCY = '60T'
|
||||||
|
# CANDLES_FREQUENCY = '30T'
|
||||||
|
CANDLES_FREQUENCY = '1T'
|
||||||
|
CANDLES_BUFFER_SIZE = 48
|
||||||
|
COIN_PAIR = 'btc_usd'
|
||||||
|
# COIN_PAIR = 'btc_usdt'
|
||||||
|
"""
|
||||||
|
Coin pair used on this simulation
|
||||||
|
"""
|
||||||
|
|
||||||
|
# TRANSACTIONS
|
||||||
|
COMMISSION_FEE = 0.0030
|
||||||
|
BUY_MIN_AMOUNT = 5 # i.e: USD
|
||||||
|
SELL_MIN_AMOUNT = 0.001 # i.e: USD
|
||||||
|
BUY_SELL_PERCENTAGE = 1 # 0.50
|
||||||
|
BUY_PERCENTAGE = BUY_SELL_PERCENTAGE
|
||||||
|
SELL_PERCENTAGE = BUY_SELL_PERCENTAGE
|
||||||
|
|
||||||
|
BASE_PRICE = 'close'
|
||||||
|
"""
|
||||||
|
Base price used (close / Heiken Ashi)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
log = None
|
||||||
|
parameters = None
|
||||||
|
|
||||||
|
|
||||||
|
def print_facts(context):
|
||||||
|
context.log.info("""
|
||||||
|
Index: {}
|
||||||
|
Date: {}
|
||||||
|
Candle:
|
||||||
|
O: {}
|
||||||
|
H: {}
|
||||||
|
L: {}
|
||||||
|
C: {}
|
||||||
|
V: {}
|
||||||
|
Metrics:
|
||||||
|
...
|
||||||
|
Portfolio:
|
||||||
|
Base price: {}
|
||||||
|
Base coin (coin2/usd): {}
|
||||||
|
Amount (coin1/btc): {}
|
||||||
|
""".format(
|
||||||
|
# Facts
|
||||||
|
context.i,
|
||||||
|
context.curr_minute,
|
||||||
|
context.candles_open[-1],
|
||||||
|
context.candles_high[-1],
|
||||||
|
context.candles_low[-1],
|
||||||
|
context.candles_close[-1],
|
||||||
|
context.candles_volume[-1],
|
||||||
|
# Metrics
|
||||||
|
# ...
|
||||||
|
# Portfolio
|
||||||
|
context.curr_base_price,
|
||||||
|
context.portfolio.cash,
|
||||||
|
context.portfolio.positions[context.coin_pair].amount,
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
def print_facts_telegram(context):
|
||||||
|
price = context.curr_base_price
|
||||||
|
amount = context.portfolio.positions[context.coin_pair].amount
|
||||||
|
pnl = context.portfolio.pnl
|
||||||
|
capital_used = context.portfolio.capital_used
|
||||||
|
portfolio_value = context.portfolio.portfolio_value
|
||||||
|
portfolio_returns = context.portfolio.returns
|
||||||
|
starting_cash = context.portfolio.starting_cash
|
||||||
|
cash = context.portfolio.cash
|
||||||
|
|
||||||
|
msg = """
|
||||||
|
Status...
|
||||||
|
Price: {}
|
||||||
|
Starting cash: {}
|
||||||
|
Cash: {}
|
||||||
|
Capital used: {}
|
||||||
|
Amount: {}
|
||||||
|
Portfolio value: {}
|
||||||
|
Returns: {}
|
||||||
|
PnL: {}
|
||||||
|
""".format(
|
||||||
|
price,
|
||||||
|
starting_cash,
|
||||||
|
cash,
|
||||||
|
capital_used,
|
||||||
|
amount,
|
||||||
|
portfolio_value,
|
||||||
|
portfolio_returns,
|
||||||
|
pnl,
|
||||||
|
)
|
||||||
|
if hasattr(context, 'telegram_bot') and context.telegram_bot is not None:
|
||||||
|
context.telegram_bot.msg(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def default_initialize(context):
|
||||||
|
# FIXME: set_benchmark
|
||||||
|
# set_benchmark(symbol(context.parameters.COIN_PAIR))
|
||||||
|
|
||||||
|
context.coin_pair = symbol(context.parameters.COIN_PAIR)
|
||||||
|
context.base_price = None
|
||||||
|
context.current_day = None
|
||||||
|
context.counter = -1
|
||||||
|
context.i = 0
|
||||||
|
|
||||||
|
context.candles_sample_rate = context.parameters.CANDLES_SAMPLE_RATE
|
||||||
|
context.candles_frequency = context.parameters.CANDLES_FREQUENCY
|
||||||
|
context.candles_buffer_size = context.parameters.CANDLES_BUFFER_SIZE
|
||||||
|
context.set_commission(
|
||||||
|
commission.PerShare(cost=context.parameters.COMMISSION_FEE))
|
||||||
|
|
||||||
|
|
||||||
|
def default_handle_data(context, data):
|
||||||
|
context.curr_minute = data.current_dt
|
||||||
|
context.counter += 1
|
||||||
|
|
||||||
|
if context.candles_sample_rate == 1:
|
||||||
|
context.i += 1
|
||||||
|
elif context.counter % context.candles_sample_rate != 0:
|
||||||
|
context.i += 1
|
||||||
|
return
|
||||||
|
|
||||||
|
if context.i < context.parameters.SKIP_FIRST_CANDLES:
|
||||||
|
return
|
||||||
|
|
||||||
|
context.candles_open = data.history(
|
||||||
|
context.coin_pair,
|
||||||
|
'open',
|
||||||
|
bar_count=context.candles_buffer_size,
|
||||||
|
frequency=context.candles_frequency)
|
||||||
|
context.candles_high = data.history(
|
||||||
|
context.coin_pair,
|
||||||
|
'high',
|
||||||
|
bar_count=context.candles_buffer_size,
|
||||||
|
frequency=context.candles_frequency)
|
||||||
|
context.candles_low = data.history(
|
||||||
|
context.coin_pair,
|
||||||
|
'low',
|
||||||
|
bar_count=context.candles_buffer_size,
|
||||||
|
frequency=context.candles_frequency)
|
||||||
|
context.candles_close = data.history(
|
||||||
|
context.coin_pair,
|
||||||
|
'price',
|
||||||
|
bar_count=context.candles_buffer_size,
|
||||||
|
frequency=context.candles_frequency)
|
||||||
|
context.candles_volume = data.history(
|
||||||
|
context.coin_pair,
|
||||||
|
'volume',
|
||||||
|
bar_count=context.candles_buffer_size,
|
||||||
|
frequency=context.candles_frequency)
|
||||||
|
|
||||||
|
# FIXME: Here is the error!
|
||||||
|
# The candles_close frame shows more or less always a value of 94, while
|
||||||
|
# bitcoin price is very different from that
|
||||||
|
print(context.candles_close)
|
||||||
|
|
||||||
|
context.base_prices = context.candles_close
|
||||||
|
cash = context.portfolio.cash
|
||||||
|
amount = context.portfolio.positions[context.coin_pair].amount
|
||||||
|
price = data.current(context.coin_pair, 'price')
|
||||||
|
order_id = None
|
||||||
|
context.last_base_price = context.base_prices[-2]
|
||||||
|
context.curr_base_price = context.base_prices[-1]
|
||||||
|
|
||||||
|
# TA calculations
|
||||||
|
# ...
|
||||||
|
|
||||||
|
# Sanity checks
|
||||||
|
# assert cash >= 0
|
||||||
|
if cash < 0:
|
||||||
|
import ipdb;
|
||||||
|
ipdb.set_trace() # BREAKPOINT
|
||||||
|
|
||||||
|
print_facts(context)
|
||||||
|
print_facts_telegram(context)
|
||||||
|
|
||||||
|
# Order management
|
||||||
|
net_shares = 0
|
||||||
|
if context.counter == 2:
|
||||||
|
brute_shares = (cash / price) * context.parameters.BUY_PERCENTAGE
|
||||||
|
share_commission_fee = brute_shares * context.parameters.COMMISSION_FEE
|
||||||
|
net_shares = brute_shares - share_commission_fee
|
||||||
|
buy_order_id = order(context.coin_pair, net_shares)
|
||||||
|
|
||||||
|
if context.counter == 3:
|
||||||
|
brute_shares = amount * context.parameters.SELL_PERCENTAGE
|
||||||
|
share_commission_fee = brute_shares * context.parameters.COMMISSION_FEE
|
||||||
|
net_shares = -(brute_shares - share_commission_fee)
|
||||||
|
sell_order_id = order(context.coin_pair, net_shares)
|
||||||
|
|
||||||
|
# Record
|
||||||
|
record(
|
||||||
|
price=price,
|
||||||
|
foo='bar',
|
||||||
|
# volume=current['volume'],
|
||||||
|
# price_change=price_change,
|
||||||
|
# Metrics
|
||||||
|
cash=cash,
|
||||||
|
# buy=context.buy,
|
||||||
|
# sell=context.sell
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def default_analyze(context=None, perf=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def initialize(context):
|
||||||
|
global log
|
||||||
|
context.parameters = parameters
|
||||||
|
context.log = Logger(context.parameters.ALGO_NAMESPACE)
|
||||||
|
log = context.log
|
||||||
|
default_initialize(context)
|
||||||
|
context.killer = GracefulKiller(context)
|
||||||
|
context.telegram_bot = None
|
||||||
|
|
||||||
|
# TELEGRAM_TOKEN='token'
|
||||||
|
# context.telegram_bot = TelegramBot()
|
||||||
|
# context.telegram_bot.initialize(TELEGRAM_TOKEN, context)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Parameters:
|
||||||
|
parameters = SimulationParameters()
|
||||||
|
start_date = pd.to_datetime(parameters.START_DATE, utc=True)
|
||||||
|
end_date = pd.to_datetime(parameters.END_DATE, utc=True)
|
||||||
|
|
||||||
|
if parameters.MODE == 'backtest':
|
||||||
|
results = run_algorithm(
|
||||||
|
capital_base=parameters.CAPITAL_BASE,
|
||||||
|
data_frequency=parameters.DATA_FREQUECY,
|
||||||
|
initialize=initialize,
|
||||||
|
handle_data=default_handle_data,
|
||||||
|
analyze=default_analyze,
|
||||||
|
exchange_name=parameters.EXCHANGE_NAME,
|
||||||
|
algo_namespace=parameters.ALGO_NAMESPACE,
|
||||||
|
base_currency=parameters.BASE_CURRENCY,
|
||||||
|
start=start_date,
|
||||||
|
end=end_date,
|
||||||
|
live=False,
|
||||||
|
live_graph=False
|
||||||
|
)
|
||||||
|
|
||||||
|
returns_daily = results
|
||||||
|
results.to_csv('{}'.format(parameters.ALGO_NAMESPACE_RESULTS_TABLE))
|
||||||
|
|
||||||
|
# returns_daily = returns_minutely.add(1).groupby(pd.TimeGrouper('24H')).prod().add(-1)
|
||||||
|
|
||||||
|
# FIXME: pyfolio integration
|
||||||
|
# pf_data = pyfolio.utils.extract_rets_pos_txn_from_zipline(results)
|
||||||
|
# pf_data = pyfolio.utils.extract_rets_pos_txn_from_zipline(results[:'2017-01-01'])
|
||||||
|
# pyfolio.create_full_tear_sheet(*pf_data)
|
||||||
|
|
||||||
|
elif parameters.MODE == 'paper':
|
||||||
|
results = run_algorithm(
|
||||||
|
capital_base=parameters.CAPITAL_BASE,
|
||||||
|
data_frequency=parameters.DATA_FREQUECY,
|
||||||
|
initialize=initialize,
|
||||||
|
handle_data=default_handle_data,
|
||||||
|
analyze=default_analyze,
|
||||||
|
exchange_name=parameters.EXCHANGE_NAME,
|
||||||
|
algo_namespace=parameters.ALGO_NAMESPACE,
|
||||||
|
base_currency=parameters.BASE_CURRENCY,
|
||||||
|
live=True,
|
||||||
|
simulate_orders=True,
|
||||||
|
live_graph=False
|
||||||
|
)
|
||||||
|
|
||||||
|
elif parameters.MODE == 'live':
|
||||||
|
results = run_algorithm(
|
||||||
|
initialize=initialize,
|
||||||
|
handle_data=default_handle_data,
|
||||||
|
analyze=default_analyze,
|
||||||
|
exchange_name=parameters.EXCHANGE_NAME,
|
||||||
|
algo_namespace=parameters.ALGO_NAMESPACE,
|
||||||
|
base_currency=parameters.BASE_CURRENCY,
|
||||||
|
live=True,
|
||||||
|
live_graph=True
|
||||||
|
)
|
||||||
@@ -55,6 +55,7 @@ class _RunAlgoError(click.ClickException, ValueError):
|
|||||||
----------
|
----------
|
||||||
pyfunc_msg : str
|
pyfunc_msg : str
|
||||||
The message that will be shown when called as a python function.
|
The message that will be shown when called as a python function.
|
||||||
|
|
||||||
cmdline_msg : str
|
cmdline_msg : str
|
||||||
The message that will be shown on the command line.
|
The message that will be shown on the command line.
|
||||||
"""
|
"""
|
||||||
@@ -416,7 +417,8 @@ def run_algorithm(initialize,
|
|||||||
auth_aliases=None,
|
auth_aliases=None,
|
||||||
stats_output=None,
|
stats_output=None,
|
||||||
output=os.devnull):
|
output=os.devnull):
|
||||||
"""Run a trading algorithm.
|
"""
|
||||||
|
Run a trading algorithm.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@@ -458,7 +460,7 @@ def run_algorithm(initialize,
|
|||||||
This argument is mutually exclusive with ``data``.
|
This argument is mutually exclusive with ``data``.
|
||||||
default_extension : bool, optional
|
default_extension : bool, optional
|
||||||
Should the default catalyst extension be loaded. This is found at
|
Should the default catalyst extension be loaded. This is found at
|
||||||
``$ZIPLINE_ROOT/extension.py``
|
``$CATALYST_ROOT/extension.py``
|
||||||
extensions : iterable[str], optional
|
extensions : iterable[str], optional
|
||||||
The names of any other extensions to load. Each element may either be
|
The names of any other extensions to load. Each element may either be
|
||||||
a dotted module path like ``a.b.c`` or a path to a python file ending
|
a dotted module path like ``a.b.c`` or a path to a python file ending
|
||||||
@@ -469,12 +471,8 @@ def run_algorithm(initialize,
|
|||||||
environ : mapping[str -> str], optional
|
environ : mapping[str -> str], optional
|
||||||
The os environment to use. Many extensions use this to get parameters.
|
The os environment to use. Many extensions use this to get parameters.
|
||||||
This defaults to ``os.environ``.
|
This defaults to ``os.environ``.
|
||||||
live: execute live trading
|
live : bool, optional
|
||||||
exchange_conn: The exchange connection parameters
|
Execute algorithm in live trading mode.
|
||||||
|
|
||||||
Supported Exchanges
|
|
||||||
-------------------
|
|
||||||
bitfinex
|
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
|||||||
+173
-179
@@ -4,7 +4,7 @@ API Reference
|
|||||||
Running a Backtest
|
Running a Backtest
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. autofunction:: zipline.run_algorithm(...)
|
.. autofunction:: catalyst.run_algorithm(...)
|
||||||
|
|
||||||
Algorithm API
|
Algorithm API
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
@@ -18,341 +18,335 @@ currently-executing :class:`~zipline.algorithm.TradingAlgorithm` instance.
|
|||||||
Data Object
|
Data Object
|
||||||
```````````
|
```````````
|
||||||
|
|
||||||
.. autoclass:: zipline.protocol.BarData
|
.. autoclass:: catalyst.protocol.BarData
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
Scheduling Functions
|
Scheduling Functions
|
||||||
````````````````````
|
````````````````````
|
||||||
|
|
||||||
.. autofunction:: zipline.api.schedule_function
|
.. autofunction:: catalyst.api.schedule_function
|
||||||
|
|
||||||
.. autoclass:: zipline.api.date_rules
|
.. autoclass:: catalyst.api.date_rules
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
|
|
||||||
.. autoclass:: zipline.api.time_rules
|
.. autoclass:: catalyst.api.time_rules
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
Orders
|
Orders
|
||||||
``````
|
``````
|
||||||
|
|
||||||
.. autofunction:: zipline.api.order
|
.. autofunction:: catalyst.api.order
|
||||||
|
|
||||||
.. autofunction:: zipline.api.order_value
|
.. autofunction:: catalyst.api.order_value
|
||||||
|
|
||||||
.. autofunction:: zipline.api.order_percent
|
.. autofunction:: catalyst.api.order_percent
|
||||||
|
|
||||||
.. autofunction:: zipline.api.order_target
|
.. autofunction:: catalyst.api.order_target
|
||||||
|
|
||||||
.. autofunction:: zipline.api.order_target_value
|
.. autofunction:: catalyst.api.order_target_value
|
||||||
|
|
||||||
.. autofunction:: zipline.api.order_target_percent
|
.. autofunction:: catalyst.api.order_target_percent
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.execution.ExecutionStyle
|
.. autoclass:: catalyst.finance.execution.ExecutionStyle
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.execution.MarketOrder
|
.. autoclass:: catalyst.finance.execution.MarketOrder
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.execution.LimitOrder
|
.. autoclass:: catalyst.finance.execution.LimitOrder
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.execution.StopOrder
|
.. autoclass:: catalyst.finance.execution.StopOrder
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.execution.StopLimitOrder
|
.. autoclass:: catalyst.finance.execution.StopLimitOrder
|
||||||
|
|
||||||
.. autofunction:: zipline.api.get_order
|
.. autofunction:: catalyst.api.get_order
|
||||||
|
|
||||||
.. autofunction:: zipline.api.get_open_orders
|
.. autofunction:: catalyst.api.get_open_orders
|
||||||
|
|
||||||
.. autofunction:: zipline.api.cancel_order
|
.. autofunction:: catalyst.api.cancel_order
|
||||||
|
|
||||||
Order Cancellation Policies
|
Order Cancellation Policies
|
||||||
'''''''''''''''''''''''''''
|
'''''''''''''''''''''''''''
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_cancel_policy
|
.. autofunction:: catalyst.api.set_cancel_policy
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.cancel_policy.CancelPolicy
|
.. autoclass:: catalyst.finance.cancel_policy.CancelPolicy
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autofunction:: zipline.api.EODCancel
|
.. autofunction:: catalyst.api.EODCancel
|
||||||
|
|
||||||
.. autofunction:: zipline.api.NeverCancel
|
.. autofunction:: catalyst.api.NeverCancel
|
||||||
|
|
||||||
|
|
||||||
Assets
|
Assets
|
||||||
``````
|
``````
|
||||||
|
|
||||||
.. autofunction:: zipline.api.symbol
|
.. autofunction:: catalyst.api.symbol
|
||||||
|
|
||||||
.. autofunction:: zipline.api.symbols
|
.. autofunction:: catalyst.api.symbols
|
||||||
|
|
||||||
.. autofunction:: zipline.api.future_symbol
|
.. autofunction:: catalyst.api.set_symbol_lookup_date
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_symbol_lookup_date
|
.. autofunction:: catalyst.api.sid
|
||||||
|
|
||||||
.. autofunction:: zipline.api.sid
|
|
||||||
|
|
||||||
|
|
||||||
Trading Controls
|
Trading Controls
|
||||||
````````````````
|
````````````````
|
||||||
|
|
||||||
Zipline provides trading controls to help ensure that the algorithm is
|
zipline provides trading controls to help ensure that the algorithm is
|
||||||
performing as expected. The functions help protect the algorithm from certian
|
performing as expected. The functions help protect the algorithm from certian
|
||||||
bugs that could cause undesirable behavior when trading with real money.
|
bugs that could cause undesirable behavior when trading with real money.
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_do_not_order_list
|
.. autofunction:: catalyst.api.set_do_not_order_list
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_long_only
|
.. autofunction:: catalyst.api.set_long_only
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_max_leverage
|
.. autofunction:: catalyst.api.set_max_leverage
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_max_order_count
|
.. autofunction:: catalyst.api.set_max_order_count
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_max_order_size
|
.. autofunction:: catalyst.api.set_max_order_size
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_max_position_size
|
.. autofunction:: catalyst.api.set_max_position_size
|
||||||
|
|
||||||
|
|
||||||
Simulation Parameters
|
Simulation Parameters
|
||||||
`````````````````````
|
`````````````````````
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_benchmark
|
.. autofunction:: catalyst.api.set_benchmark
|
||||||
|
|
||||||
Commission Models
|
Commission Models
|
||||||
'''''''''''''''''
|
'''''''''''''''''
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_commission
|
.. autofunction:: catalyst.api.set_commission
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.commission.CommissionModel
|
.. autoclass:: catalyst.finance.commission.CommissionModel
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.commission.PerShare
|
.. autoclass:: catalyst.finance.commission.PerShare
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.commission.PerTrade
|
.. autoclass:: catalyst.finance.commission.PerTrade
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.commission.PerDollar
|
.. autoclass:: catalyst.finance.commission.PerDollar
|
||||||
|
|
||||||
Slippage Models
|
Slippage Models
|
||||||
'''''''''''''''
|
'''''''''''''''
|
||||||
|
|
||||||
.. autofunction:: zipline.api.set_slippage
|
.. autofunction:: catalyst.api.set_slippage
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.slippage.SlippageModel
|
.. autoclass:: catalyst.finance.slippage.SlippageModel
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.slippage.FixedSlippage
|
.. autoclass:: catalyst.finance.slippage.FixedSlippage
|
||||||
|
|
||||||
.. autoclass:: zipline.finance.slippage.VolumeShareSlippage
|
.. autoclass:: catalyst.finance.slippage.VolumeShareSlippage
|
||||||
|
|
||||||
Pipeline
|
Pipeline
|
||||||
````````
|
````````
|
||||||
|
|
||||||
For more information, see :ref:`pipeline-api`
|
Not supported yet.
|
||||||
|
|
||||||
.. autofunction:: zipline.api.attach_pipeline
|
.. For more information, see :ref:`pipeline-api`
|
||||||
|
|
||||||
.. autofunction:: zipline.api.pipeline_output
|
.. .. autofunction:: catalyst.api.attach_pipeline
|
||||||
|
|
||||||
|
.. .. autofunction:: catalyst.api.pipeline_output
|
||||||
|
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
`````````````
|
`````````````
|
||||||
|
|
||||||
.. autofunction:: zipline.api.record
|
.. autofunction:: catalyst.api.record
|
||||||
|
|
||||||
.. autofunction:: zipline.api.get_environment
|
.. autofunction:: catalyst.api.get_environment
|
||||||
|
|
||||||
.. autofunction:: zipline.api.fetch_csv
|
.. autofunction:: catalyst.api.fetch_csv
|
||||||
|
|
||||||
|
|
||||||
.. _pipeline-api:
|
.. _pipeline-api:
|
||||||
|
|
||||||
Pipeline API
|
.. Pipeline API
|
||||||
~~~~~~~~~~~~
|
.. ~~~~~~~~~~~~
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.Pipeline
|
.. .. autoclass:: zipline.pipeline.Pipeline
|
||||||
:members:
|
.. :members:
|
||||||
:member-order: groupwise
|
.. :member-order: groupwise
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.CustomFactor
|
.. .. autoclass:: zipline.pipeline.CustomFactor
|
||||||
:members:
|
.. :members:
|
||||||
:member-order: groupwise
|
.. :member-order: groupwise
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.filters.Filter
|
.. .. autoclass:: zipline.pipeline.filters.Filter
|
||||||
:members: __and__, __or__
|
.. :members: __and__, __or__
|
||||||
:exclude-members: dtype
|
.. :exclude-members: dtype
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.Factor
|
.. .. autoclass:: zipline.pipeline.factors.Factor
|
||||||
:members: bottom, deciles, demean, linear_regression, pearsonr,
|
.. :members: bottom, deciles, demean, linear_regression, pearsonr,
|
||||||
percentile_between, quantiles, quartiles, quintiles, rank,
|
.. percentile_between, quantiles, quartiles, quintiles, rank,
|
||||||
spearmanr, top, winsorize, zscore, isnan, notnan, isfinite, eq,
|
.. spearmanr, top, winsorize, zscore, isnan, notnan, isfinite, eq,
|
||||||
__add__, __sub__, __mul__, __div__, __mod__, __pow__, __lt__,
|
.. \__add__, \__sub__, \__mul__, \__div__, \__mod__, \__pow__,
|
||||||
__le__, __ne__, __ge__, __gt__
|
.. \__lt__, \__le__, \__ne__, \__ge__, \__gt__
|
||||||
:exclude-members: dtype
|
.. :exclude-members: dtype
|
||||||
:member-order: bysource
|
.. :member-order: bysource
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.term.Term
|
.. .. autoclass:: zipline.pipeline.term.Term
|
||||||
:members:
|
.. :members:
|
||||||
:exclude-members: compute_extra_rows, dependencies, inputs, mask, windowed
|
.. :exclude-members: compute_extra_rows, dependencies, inputs, mask, windowed
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.data.USEquityPricing
|
.. .. autoclass:: zipline.pipeline.data.USEquityPricing
|
||||||
:members: open, high, low, close, volume
|
.. :members: open, high, low, close, volume
|
||||||
:undoc-members:
|
.. :undoc-members:
|
||||||
|
|
||||||
Built-in Factors
|
.. Built-in Factors
|
||||||
````````````````
|
.. ````````````````
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.AverageDollarVolume
|
.. .. autoclass:: zipline.pipeline.factors.AverageDollarVolume
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.BollingerBands
|
.. .. autoclass:: zipline.pipeline.factors.BollingerBands
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.BusinessDaysSincePreviousEvent
|
.. .. autoclass:: zipline.pipeline.factors.BusinessDaysSincePreviousEvent
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.BusinessDaysUntilNextEvent
|
.. .. autoclass:: zipline.pipeline.factors.BusinessDaysUntilNextEvent
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.ExponentialWeightedMovingAverage
|
.. .. autoclass:: zipline.pipeline.factors.ExponentialWeightedMovingAverage
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.ExponentialWeightedMovingStdDev
|
.. .. autoclass:: zipline.pipeline.factors.ExponentialWeightedMovingStdDev
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.Latest
|
.. .. autoclass:: zipline.pipeline.factors.Latest
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.MaxDrawdown
|
.. .. autoclass:: zipline.pipeline.factors.MaxDrawdown
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.Returns
|
.. .. autoclass:: zipline.pipeline.factors.Returns
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.RollingLinearRegressionOfReturns
|
.. .. autoclass:: zipline.pipeline.factors.RollingLinearRegressionOfReturns
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.RollingPearsonOfReturns
|
.. .. autoclass:: zipline.pipeline.factors.RollingPearsonOfReturns
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.RollingSpearmanOfReturns
|
.. .. autoclass:: zipline.pipeline.factors.RollingSpearmanOfReturns
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.RSI
|
.. .. autoclass:: zipline.pipeline.factors.RSI
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.SimpleMovingAverage
|
.. .. autoclass:: zipline.pipeline.factors.SimpleMovingAverage
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.VWAP
|
.. .. autoclass:: zipline.pipeline.factors.VWAP
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.factors.WeightedAverageValue
|
.. .. autoclass:: zipline.pipeline.factors.WeightedAverageValue
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
Pipeline Engine
|
.. Pipeline Engine
|
||||||
```````````````
|
.. ```````````````
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.engine.PipelineEngine
|
.. .. autoclass:: zipline.pipeline.engine.PipelineEngine
|
||||||
:members: run_pipeline, run_chunked_pipeline
|
.. :members: run_pipeline, run_chunked_pipeline
|
||||||
:member-order: bysource
|
.. :member-order: bysource
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.engine.SimplePipelineEngine
|
.. .. autoclass:: zipline.pipeline.engine.SimplePipelineEngine
|
||||||
:members: __init__, run_pipeline, run_chunked_pipeline
|
.. :members: __init__, run_pipeline, run_chunked_pipeline
|
||||||
:member-order: bysource
|
.. :member-order: bysource
|
||||||
|
|
||||||
.. autofunction:: zipline.pipeline.engine.default_populate_initial_workspace
|
.. .. autofunction:: zipline.pipeline.engine.default_populate_initial_workspace
|
||||||
|
|
||||||
Data Loaders
|
.. Data Loaders
|
||||||
````````````
|
.. ````````````
|
||||||
|
|
||||||
.. autoclass:: zipline.pipeline.loaders.equity_pricing_loader.USEquityPricingLoader
|
.. .. autoclass:: zipline.pipeline.loaders.equity_pricing_loader.USEquityPricingLoader
|
||||||
:members: __init__, from_files, load_adjusted_array
|
.. :members: __init__, from_files, load_adjusted_array
|
||||||
:member-order: bysource
|
.. :member-order: bysource
|
||||||
|
|
||||||
Asset Metadata
|
Asset Metadata
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. autoclass:: zipline.assets.Asset
|
.. autoclass:: catalyst.assets.Asset
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autoclass:: zipline.assets.Equity
|
.. autoclass:: catalyst.assets.AssetConvertible
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: zipline.assets.Future
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: zipline.assets.AssetConvertible
|
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
Trading Calendar API
|
Trading Calendar API
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. autofunction:: zipline.utils.calendars.get_calendar
|
.. autofunction:: catalyst.utils.calendars.get_calendar
|
||||||
|
|
||||||
.. autoclass:: zipline.utils.calendars.TradingCalendar
|
.. autoclass:: catalyst.utils.calendars.TradingCalendar
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
.. autofunction:: zipline.utils.calendars.register_calendar
|
.. autofunction:: catalyst.utils.calendars.register_calendar
|
||||||
|
|
||||||
.. autofunction:: zipline.utils.calendars.register_calendar_type
|
.. autofunction:: catalyst.utils.calendars.register_calendar_type
|
||||||
|
|
||||||
.. autofunction:: zipline.utils.calendars.deregister_calendar
|
.. autofunction:: catalyst.utils.calendars.deregister_calendar
|
||||||
|
|
||||||
.. autofunction:: zipline.utils.calendars.clear_calendars
|
.. autofunction:: catalyst.utils.calendars.clear_calendars
|
||||||
|
|
||||||
|
|
||||||
Data API
|
Data API
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
Writers
|
.. Writers
|
||||||
```````
|
.. ```````
|
||||||
.. autoclass:: zipline.data.minute_bars.BcolzMinuteBarWriter
|
.. .. autoclass:: zipline.data.minute_bars.BcolzMinuteBarWriter
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.data.us_equity_pricing.BcolzDailyBarWriter
|
.. .. autoclass:: zipline.data.us_equity_pricing.BcolzDailyBarWriter
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.data.us_equity_pricing.SQLiteAdjustmentWriter
|
.. .. autoclass:: zipline.data.us_equity_pricing.SQLiteAdjustmentWriter
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.assets.AssetDBWriter
|
.. .. autoclass:: zipline.assets.AssetDBWriter
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
Readers
|
.. Readers
|
||||||
```````
|
.. ```````
|
||||||
.. autoclass:: zipline.data.minute_bars.BcolzMinuteBarReader
|
.. .. autoclass:: zipline.data.minute_bars.BcolzMinuteBarReader
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.data.us_equity_pricing.BcolzDailyBarReader
|
.. .. autoclass:: zipline.data.us_equity_pricing.BcolzDailyBarReader
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.data.us_equity_pricing.SQLiteAdjustmentReader
|
.. .. autoclass:: zipline.data.us_equity_pricing.SQLiteAdjustmentReader
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.assets.AssetFinder
|
.. .. autoclass:: zipline.assets.AssetFinder
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
.. autoclass:: zipline.data.data_portal.DataPortal
|
.. .. autoclass:: zipline.data.data_portal.DataPortal
|
||||||
:members:
|
.. :members:
|
||||||
|
|
||||||
Bundles
|
.. Bundles
|
||||||
```````
|
.. ```````
|
||||||
.. autofunction:: zipline.data.bundles.register
|
.. .. autofunction:: zipline.data.bundles.register
|
||||||
|
|
||||||
.. autofunction:: zipline.data.bundles.ingest(name, environ=os.environ, date=None, show_progress=True)
|
.. .. autofunction:: zipline.data.bundles.ingest(name, environ=os.environ, date=None, show_progress=True)
|
||||||
|
|
||||||
.. autofunction:: zipline.data.bundles.load(name, environ=os.environ, date=None)
|
.. .. autofunction:: zipline.data.bundles.load(name, environ=os.environ, date=None)
|
||||||
|
|
||||||
.. autofunction:: zipline.data.bundles.unregister
|
.. .. autofunction:: zipline.data.bundles.unregister
|
||||||
|
|
||||||
.. data:: zipline.data.bundles.bundles
|
.. .. data:: zipline.data.bundles.bundles
|
||||||
|
|
||||||
The bundles that have been registered as a mapping from bundle name to bundle
|
.. The bundles that have been registered as a mapping from bundle name to bundle
|
||||||
data. This mapping is immutable and should only be updated through
|
.. data. This mapping is immutable and should only be updated through
|
||||||
:func:`~zipline.data.bundles.register` or
|
.. :func:`~zipline.data.bundles.register` or
|
||||||
:func:`~zipline.data.bundles.unregister`.
|
.. :func:`~zipline.data.bundles.unregister`.
|
||||||
|
|
||||||
.. autofunction:: zipline.data.bundles.yahoo_equities
|
.. .. autofunction:: zipline.data.bundles.yahoo_equities
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -362,16 +356,16 @@ Utilities
|
|||||||
Caching
|
Caching
|
||||||
```````
|
```````
|
||||||
|
|
||||||
.. autoclass:: zipline.utils.cache.CachedObject
|
.. autoclass:: catalyst.utils.cache.CachedObject
|
||||||
|
|
||||||
.. autoclass:: zipline.utils.cache.ExpiringCache
|
.. autoclass:: catalyst.utils.cache.ExpiringCache
|
||||||
|
|
||||||
.. autoclass:: zipline.utils.cache.dataframe_cache
|
.. autoclass:: catalyst.utils.cache.dataframe_cache
|
||||||
|
|
||||||
.. autoclass:: zipline.utils.cache.working_file
|
.. autoclass:: catalyst.utils.cache.working_file
|
||||||
|
|
||||||
.. autoclass:: zipline.utils.cache.working_dir
|
.. autoclass:: catalyst.utils.cache.working_dir
|
||||||
|
|
||||||
Command Line
|
Command Line
|
||||||
````````````
|
````````````
|
||||||
.. autofunction:: zipline.utils.cli.maybe_show_progress
|
.. autofunction:: catalyst.utils.cli.maybe_show_progress
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ We'll start with the CLI, and introduce the ``run_algorithm()`` in the last
|
|||||||
example of this tutorial. Some of the :doc:`example algorithms <example-algos>`
|
example of this tutorial. Some of the :doc:`example algorithms <example-algos>`
|
||||||
provide instructions on how to run them both from the CLI, and using the
|
provide instructions on how to run them both from the CLI, and using the
|
||||||
:func:`~catalyst.run_algorithm` function. For the third method, refer to the
|
:func:`~catalyst.run_algorithm` function. For the third method, refer to the
|
||||||
corresponding section on :doc:`Catalyst & Jupyter Notebook <jupyter>` after you
|
corresponding section on :ref:`Catalyst & Jupyter Notebook <jupyter>` after you
|
||||||
have assimilated the contents of this tutorial.
|
have assimilated the contents of this tutorial.
|
||||||
|
|
||||||
Command line interface
|
Command line interface
|
||||||
@@ -473,6 +473,7 @@ Which we execute by running:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
|
||||||
|
|
||||||
There is a row for each trading day, starting on the first day of our
|
There is a row for each trading day, starting on the first day of our
|
||||||
simulation Jan 1st, 2016. In the columns you can find various
|
simulation Jan 1st, 2016. In the columns you can find various
|
||||||
information about the state of your algorithm. The column
|
information about the state of your algorithm. The column
|
||||||
@@ -518,7 +519,7 @@ alongside enigma-catalyst (with the exception of the ``Conda`` install, where it
|
|||||||
was included by default inside the conda environment we created). If for any
|
was included by default inside the conda environment we created). If for any
|
||||||
reason you don't have it installed, you can add it by running:
|
reason you don't have it installed, you can add it by running:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: bash
|
||||||
|
|
||||||
(catalyst)$ pip install matplotlib
|
(catalyst)$ pip install matplotlib
|
||||||
|
|
||||||
@@ -806,6 +807,7 @@ the ``scikit-learn`` functions require ``numpy.ndarray``\ s rather than
|
|||||||
``pandas.DataFrame``\ s, so you can simply pass the underlying
|
``pandas.DataFrame``\ s, so you can simply pass the underlying
|
||||||
``ndarray`` of a ``DataFrame`` via ``.values``).
|
``ndarray`` of a ``DataFrame`` via ``.values``).
|
||||||
|
|
||||||
|
.. _jupyter:
|
||||||
|
|
||||||
Jupyter Notebook
|
Jupyter Notebook
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
@@ -826,13 +828,13 @@ In order to use Jupyter Notebook, you first have to install it inside your
|
|||||||
environment. It's available as ``pip`` package, so regardless of how you
|
environment. It's available as ``pip`` package, so regardless of how you
|
||||||
installed Catalyst, go inside your catalyst environemnt and run:
|
installed Catalyst, go inside your catalyst environemnt and run:
|
||||||
|
|
||||||
.. code:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
(catalyst)$ pip install jupyter
|
(catalyst)$ pip install jupyter
|
||||||
|
|
||||||
Once you have Jupyter Notebook installed, every time you want to use it run:
|
Once you have Jupyter Notebook installed, every time you want to use it run:
|
||||||
|
|
||||||
.. code:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
(catalyst)$ jupyter notebook
|
(catalyst)$ jupyter notebook
|
||||||
|
|
||||||
@@ -846,7 +848,7 @@ Before running your algorithms inside the Jupyter Notebook, remember to ingest
|
|||||||
the data from the command line interface (CLI). In the example below, you would
|
the data from the command line interface (CLI). In the example below, you would
|
||||||
need to run first:
|
need to run first:
|
||||||
|
|
||||||
.. code:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
catalyst ingest-exchange -x bitfinex -i btc_usd
|
catalyst ingest-exchange -x bitfinex -i btc_usd
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -27,8 +27,8 @@ extlinks = {
|
|||||||
|
|
||||||
# -- Docstrings ---------------------------------------------------------------
|
# -- Docstrings ---------------------------------------------------------------
|
||||||
|
|
||||||
#extensions += ['numpydoc']
|
extensions += ['numpydoc']
|
||||||
#numpydoc_show_class_members = False
|
numpydoc_show_class_members = False
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['.templates']
|
templates_path = ['.templates']
|
||||||
@@ -97,3 +97,6 @@ intersphinx_mapping = {
|
|||||||
doctest_global_setup = "import catalyst"
|
doctest_global_setup = "import catalyst"
|
||||||
|
|
||||||
todo_include_todos = True
|
todo_include_todos = True
|
||||||
|
|
||||||
|
suppress_warnings = ['image.nonlocal_uri']
|
||||||
|
|
||||||
|
|||||||
@@ -36,25 +36,15 @@ Finally, you can build the C extensions by running:
|
|||||||
|
|
||||||
$ python setup.py build_ext --inplace
|
$ python setup.py build_ext --inplace
|
||||||
|
|
||||||
.. To finish, make sure `tests`__ pass.
|
Development with Docker
|
||||||
|
-----------------------
|
||||||
|
|
||||||
.. __ #style-guide-running-tests
|
If you want to work with zipline using a `Docker`__ container, you'll need to
|
||||||
|
build the ``Dockerfile`` in the Zipline root directory, and then build
|
||||||
|
``Dockerfile-dev``. Instructions for building both containers can be found in
|
||||||
|
``Dockerfile`` and ``Dockerfile-dev``, respectively.
|
||||||
|
|
||||||
.. If you get an error running nosetests after setting up a fresh virtualenv, please try running
|
__ https://docs.docker.com/get-started/
|
||||||
|
|
||||||
.. code-block
|
|
||||||
|
|
||||||
.. # where zipline is the name of your virtualenv
|
|
||||||
.. $ deactivate zipline
|
|
||||||
.. $ workon zipline
|
|
||||||
|
|
||||||
|
|
||||||
.. Development with Docker
|
|
||||||
.. -----------------------
|
|
||||||
|
|
||||||
..If you want to work with zipline using a `Docker`__ container, you'll need to build the ``Dockerfile`` in the Zipline root directory, and then build ``Dockerfile-dev``. Instructions for building both containers can be found in ``Dockerfile`` and ``Dockerfile-dev``, respectively.
|
|
||||||
|
|
||||||
.. __ https://docs.docker.com/get-started/
|
|
||||||
|
|
||||||
Git Branching Structure
|
Git Branching Structure
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
|
|
|
|
||||||
|
|
||||||
Example Algorithms
|
Example Algorithms
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
.. include:: ../../README.rst
|
.. include:: ../../README.rst
|
||||||
|
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
|
|
||||||
Table of Contents
|
Table of Contents
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ Troubleshooting ``pip`` Install
|
|||||||
.. _pipenv:
|
.. _pipenv:
|
||||||
|
|
||||||
Installing with ``pipenv``
|
Installing with ``pipenv``
|
||||||
-------------------------
|
--------------------------
|
||||||
|
|
||||||
Installing Catalyst via ``pipenv`` is perhaps easier that installing it via
|
Installing Catalyst via ``pipenv`` is perhaps easier that installing it via
|
||||||
``pip`` itself but you need to install ``pipenv`` first via ``pip``.
|
``pip`` itself but you need to install ``pipenv`` first via ``pip``.
|
||||||
@@ -476,6 +476,7 @@ mentioned above are as follows:
|
|||||||
default you get 0 as the Value Data)
|
default you get 0 as the Value Data)
|
||||||
|
|
||||||
|
|
|
|
||||||
|
|
||||||
- **The installer has encountered an unexpected error installing this package.
|
- **The installer has encountered an unexpected error installing this package.
|
||||||
This may indicate a problem with this package. The error code is 2503.**
|
This may indicate a problem with this package. The error code is 2503.**
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ Currency symbols (e.g. btc, eth, ltc) follow the Bittrex convention.
|
|||||||
|
|
||||||
Here are some examples:
|
Here are some examples:
|
||||||
|
|
||||||
.. code-block:: json
|
.. code:: python
|
||||||
|
|
||||||
# With Bitfinex
|
# With Bitfinex
|
||||||
bitcoin_usd_asset = symbol('btc_usd')
|
bitcoin_usd_asset = symbol('btc_usd')
|
||||||
|
|||||||
@@ -2,7 +2,23 @@
|
|||||||
Release Notes
|
Release Notes
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Version 0.5.0
|
Version 0.5.3
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
**Release Date**: 2018-02-09
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
~~~~~~~~~
|
||||||
|
- Fixed an issue with last candle in backtesting :issue:`219`
|
||||||
|
|
||||||
|
Version 0.5.2
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
**Release Date**: 2018-02-08
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
~~~~~~~~~
|
||||||
|
- Fixed an issue with live candle values :issue:`216` and :issue:`199`
|
||||||
|
|
||||||
|
Version 0.5.1
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
**Release Date**: 2018-02-07
|
**Release Date**: 2018-02-07
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Installation: MacOS
|
|||||||
|
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
|
|
||||||
Installation: Windows
|
Installation: Windows
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ Where things go smoothly:
|
|||||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/H8HqcEbZmkk" frameborder="0" allowfullscreen></iframe>
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/H8HqcEbZmkk" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
|
|
|
||||||
|
|
||||||
Where things don't:
|
Where things don't:
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
@@ -29,6 +31,7 @@ Where things don't:
|
|||||||
|
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
|
|
||||||
Backtesting a Strategy
|
Backtesting a Strategy
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@@ -44,6 +47,7 @@ sell. Hopefully, we’ll ride the waves.
|
|||||||
|
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
|
|
||||||
Live Trading a Strategy
|
Live Trading a Strategy
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
@@ -54,5 +58,6 @@ in the previous video, we now take it to trade live against the Bittrex exchange
|
|||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/NupiE-Xuglw" frameborder="0" allowfullscreen></iframe>
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/NupiE-Xuglw" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
@@ -16,7 +16,7 @@ babel==1.3
|
|||||||
docutils==0.12
|
docutils==0.12
|
||||||
snowballstemmer==1.2.0
|
snowballstemmer==1.2.0
|
||||||
sphinx-rtd-theme==0.1.8
|
sphinx-rtd-theme==0.1.8
|
||||||
sphinx==1.3.4
|
sphinx==1.6.7
|
||||||
pbr==1.10.0
|
pbr==1.10.0
|
||||||
|
|
||||||
mock==2.0.0
|
mock==2.0.0
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Sphinx>=1.3.2
|
Sphinx==1.6.7
|
||||||
numpydoc>=0.5.0
|
numpydoc>=0.5.0
|
||||||
sphinx-autobuild==0.6.0
|
sphinx-autobuild==0.6.0
|
||||||
docutils==0.12
|
docutils==0.12
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
|
|
||||||
from catalyst.testing import ZiplineTestCase
|
from catalyst.exchange.utils.stats_utils import set_print_settings
|
||||||
from catalyst.testing.fixtures import WithLogger
|
|
||||||
from .base import BaseExchangeTestCase
|
from .base import BaseExchangeTestCase
|
||||||
from catalyst.exchange.ccxt.ccxt_exchange import CCXT
|
from catalyst.exchange.ccxt.ccxt_exchange import CCXT
|
||||||
from catalyst.exchange.exchange_execution import ExchangeLimitOrder
|
from catalyst.exchange.exchange_execution import ExchangeLimitOrder
|
||||||
@@ -15,7 +14,7 @@ log = Logger('test_ccxt')
|
|||||||
class TestCCXT(BaseExchangeTestCase):
|
class TestCCXT(BaseExchangeTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setup(self):
|
def setup(self):
|
||||||
exchange_name = 'binance'
|
exchange_name = 'bittrex'
|
||||||
auth = get_exchange_auth(exchange_name)
|
auth = get_exchange_auth(exchange_name)
|
||||||
self.exchange = CCXT(
|
self.exchange = CCXT(
|
||||||
exchange_name=exchange_name,
|
exchange_name=exchange_name,
|
||||||
@@ -58,15 +57,20 @@ class TestCCXT(BaseExchangeTestCase):
|
|||||||
def test_get_candles(self):
|
def test_get_candles(self):
|
||||||
log.info('retrieving candles')
|
log.info('retrieving candles')
|
||||||
candles = self.exchange.get_candles(
|
candles = self.exchange.get_candles(
|
||||||
freq='30T',
|
freq='1T',
|
||||||
assets=[self.exchange.get_asset('eth_btc')],
|
assets=[self.exchange.get_asset('eth_btc')],
|
||||||
bar_count=200,
|
bar_count=200,
|
||||||
start_dt=pd.to_datetime('2017-09-01', utc=True)
|
# start_dt=pd.to_datetime('2017-09-01', utc=True),
|
||||||
)
|
)
|
||||||
|
|
||||||
for asset in candles:
|
for asset in candles:
|
||||||
df = pd.DataFrame(candles[asset])
|
df = pd.DataFrame(candles[asset])
|
||||||
df.set_index('last_traded', drop=True, inplace=True)
|
df.set_index('last_traded', drop=True, inplace=True)
|
||||||
|
|
||||||
|
set_print_settings()
|
||||||
|
print('got {} candles'.format(len(df)))
|
||||||
|
print(df.head(10))
|
||||||
|
print(df.tail(10))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_tickers(self):
|
def test_tickers(self):
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import random
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
from datetime import timedelta
|
||||||
from logbook import TestHandler
|
from logbook import TestHandler
|
||||||
from pandas.util.testing import assert_frame_equal
|
from pandas.util.testing import assert_frame_equal
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ from catalyst.exchange.utils.exchange_utils import get_candles_df
|
|||||||
from catalyst.exchange.utils.factory import get_exchange
|
from catalyst.exchange.utils.factory import get_exchange
|
||||||
from catalyst.exchange.utils.test_utils import output_df, \
|
from catalyst.exchange.utils.test_utils import output_df, \
|
||||||
select_random_assets
|
select_random_assets
|
||||||
|
from catalyst.exchange.utils.stats_utils import set_print_settings
|
||||||
|
|
||||||
pd.set_option('display.expand_frame_repr', False)
|
pd.set_option('display.expand_frame_repr', False)
|
||||||
pd.set_option('precision', 8)
|
pd.set_option('precision', 8)
|
||||||
@@ -58,6 +60,12 @@ class TestSuiteBundle:
|
|||||||
|
|
||||||
log_catcher = TestHandler()
|
log_catcher = TestHandler()
|
||||||
with log_catcher:
|
with log_catcher:
|
||||||
|
symbols = [asset.symbol for asset in assets]
|
||||||
|
print(
|
||||||
|
'comparing data for {}/{} with {} timeframe until {}'.format(
|
||||||
|
exchange.name, symbols, freq, end_dt
|
||||||
|
)
|
||||||
|
)
|
||||||
data['bundle'] = data_portal.get_history_window(
|
data['bundle'] = data_portal.get_history_window(
|
||||||
assets=assets,
|
assets=assets,
|
||||||
end_dt=end_dt,
|
end_dt=end_dt,
|
||||||
@@ -66,6 +74,12 @@ class TestSuiteBundle:
|
|||||||
field='close',
|
field='close',
|
||||||
data_frequency=data_frequency,
|
data_frequency=data_frequency,
|
||||||
)
|
)
|
||||||
|
set_print_settings()
|
||||||
|
print(
|
||||||
|
'the bundle first / last row:\n{}'.format(
|
||||||
|
data['bundle'].iloc[[-1, 0]]
|
||||||
|
)
|
||||||
|
)
|
||||||
candles = exchange.get_candles(
|
candles = exchange.get_candles(
|
||||||
end_dt=end_dt,
|
end_dt=end_dt,
|
||||||
freq=freq,
|
freq=freq,
|
||||||
@@ -79,6 +93,11 @@ class TestSuiteBundle:
|
|||||||
bar_count=bar_count,
|
bar_count=bar_count,
|
||||||
end_dt=end_dt,
|
end_dt=end_dt,
|
||||||
)
|
)
|
||||||
|
print(
|
||||||
|
'the exchange first / last row:\n{}'.format(
|
||||||
|
data['exchange'].iloc[[-1, 0]]
|
||||||
|
)
|
||||||
|
)
|
||||||
for source in data:
|
for source in data:
|
||||||
df = data[source]
|
df = data[source]
|
||||||
path, folder = output_df(
|
path, folder = output_df(
|
||||||
@@ -106,6 +125,65 @@ class TestSuiteBundle:
|
|||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def compare_current_with_last_candle(self, exchange, assets, end_dt,
|
||||||
|
freq, data_frequency, data_portal):
|
||||||
|
"""
|
||||||
|
Creates DataFrames from the bundle and exchange for the specified
|
||||||
|
data set.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
exchange: Exchange
|
||||||
|
assets
|
||||||
|
end_dt
|
||||||
|
bar_count
|
||||||
|
freq
|
||||||
|
data_frequency
|
||||||
|
data_portal
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
|
data = dict()
|
||||||
|
|
||||||
|
assets = sorted(assets, key=lambda a: a.symbol)
|
||||||
|
log_catcher = TestHandler()
|
||||||
|
with log_catcher:
|
||||||
|
symbols = [asset.symbol for asset in assets]
|
||||||
|
print(
|
||||||
|
'comparing data for {}/{} with {} timeframe on {}'.format(
|
||||||
|
exchange.name, symbols, freq, end_dt
|
||||||
|
)
|
||||||
|
)
|
||||||
|
data['candle'] = data_portal.get_history_window(
|
||||||
|
assets=assets,
|
||||||
|
end_dt=end_dt,
|
||||||
|
bar_count=1,
|
||||||
|
frequency=freq,
|
||||||
|
field='close',
|
||||||
|
data_frequency=data_frequency,
|
||||||
|
)
|
||||||
|
set_print_settings()
|
||||||
|
print(
|
||||||
|
'the bundle first / last row:\n{}'.format(
|
||||||
|
data['candle'].iloc[[-1]]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
current = data_portal.get_spot_value(
|
||||||
|
assets=assets,
|
||||||
|
field='close',
|
||||||
|
dt=end_dt,
|
||||||
|
data_frequency=data_frequency,
|
||||||
|
)
|
||||||
|
data['current'] = pd.Series(data=current, index=assets)
|
||||||
|
print(
|
||||||
|
'the current price:\n{}'.format(
|
||||||
|
data['current']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
pass
|
||||||
|
|
||||||
def test_validate_bundles(self):
|
def test_validate_bundles(self):
|
||||||
# exchange_population = 3
|
# exchange_population = 3
|
||||||
asset_population = 3
|
asset_population = 3
|
||||||
@@ -139,6 +217,7 @@ class TestSuiteBundle:
|
|||||||
if end_dt is None or asset_end_dt < end_dt:
|
if end_dt is None or asset_end_dt < end_dt:
|
||||||
end_dt = asset_end_dt
|
end_dt = asset_end_dt
|
||||||
|
|
||||||
|
end_dt = end_dt + timedelta(minutes=3)
|
||||||
dt_range = pd.date_range(
|
dt_range = pd.date_range(
|
||||||
end=end_dt, periods=bar_count, freq=freq
|
end=end_dt, periods=bar_count, freq=freq
|
||||||
)
|
)
|
||||||
@@ -152,3 +231,45 @@ class TestSuiteBundle:
|
|||||||
data_portal=data_portal,
|
data_portal=data_portal,
|
||||||
)
|
)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def test_validate_last_candle(self):
|
||||||
|
# exchange_population = 3
|
||||||
|
asset_population = 3
|
||||||
|
data_frequency = random.choice(['minute'])
|
||||||
|
|
||||||
|
# bundle = 'dailyBundle' if data_frequency
|
||||||
|
# == 'daily' else 'minuteBundle'
|
||||||
|
# exchanges = select_random_exchanges(
|
||||||
|
# population=exchange_population,
|
||||||
|
# features=[bundle],
|
||||||
|
# ) # Type: list[Exchange]
|
||||||
|
exchanges = [get_exchange('poloniex', skip_init=True)]
|
||||||
|
|
||||||
|
data_portal = TestSuiteBundle.get_data_portal(exchanges)
|
||||||
|
for exchange in exchanges:
|
||||||
|
exchange.init()
|
||||||
|
|
||||||
|
frequencies = exchange.get_candle_frequencies(data_frequency)
|
||||||
|
freq = random.sample(frequencies, 1)[0]
|
||||||
|
|
||||||
|
assets = select_random_assets(
|
||||||
|
exchange.assets, asset_population
|
||||||
|
)
|
||||||
|
end_dt = None
|
||||||
|
for asset in assets:
|
||||||
|
attribute = 'end_{}'.format(data_frequency)
|
||||||
|
asset_end_dt = getattr(asset, attribute)
|
||||||
|
|
||||||
|
if end_dt is None or asset_end_dt < end_dt:
|
||||||
|
end_dt = asset_end_dt
|
||||||
|
|
||||||
|
end_dt = end_dt + timedelta(minutes=3)
|
||||||
|
self.compare_current_with_last_candle(
|
||||||
|
exchange=exchange,
|
||||||
|
assets=assets,
|
||||||
|
end_dt=end_dt,
|
||||||
|
freq=freq,
|
||||||
|
data_frequency=data_frequency,
|
||||||
|
data_portal=data_portal,
|
||||||
|
)
|
||||||
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user