mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-17 11:25:55 +08:00
merging from develop
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
# limitations under the License.
|
||||
import pandas as pd
|
||||
|
||||
from catalyst import run_algorithm
|
||||
from catalyst.api import (
|
||||
order_target_value,
|
||||
symbol,
|
||||
@@ -26,7 +27,7 @@ from catalyst.api import (
|
||||
|
||||
|
||||
def initialize(context):
|
||||
context.ASSET_NAME = 'btc_usdt'
|
||||
context.ASSET_NAME = 'btc_usd'
|
||||
context.TARGET_HODL_RATIO = 0.8
|
||||
context.RESERVE_RATIO = 1.0 - context.TARGET_HODL_RATIO
|
||||
|
||||
@@ -58,6 +59,7 @@ def handle_data(context, data):
|
||||
|
||||
# Check if still buying and could (approximately) afford another purchase
|
||||
if context.is_buying and cash > price:
|
||||
print('buying')
|
||||
# Place order to make position in asset equal to target_hodl_value
|
||||
order_target_value(
|
||||
context.asset,
|
||||
@@ -91,12 +93,13 @@ def analyze(context=None, results=None):
|
||||
buys = trans.ix[
|
||||
[t[0]['amount'] > 0 for t in trans.transactions]
|
||||
]
|
||||
ax2.plot(
|
||||
buys.index,
|
||||
ax2.scatter(
|
||||
buys.index.to_pydatetime(),
|
||||
results.price[buys.index],
|
||||
'^',
|
||||
markersize=10,
|
||||
color='g',
|
||||
marker='^',
|
||||
s=100,
|
||||
c='g',
|
||||
label=''
|
||||
)
|
||||
|
||||
ax3 = plt.subplot(613, sharex=ax1)
|
||||
@@ -135,3 +138,17 @@ def analyze(context=None, results=None):
|
||||
plt.gcf().set_size_inches(18, 8)
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_algorithm(
|
||||
capital_base=10000,
|
||||
data_frequency='minute',
|
||||
initialize=initialize,
|
||||
handle_data=handle_data,
|
||||
analyze=analyze,
|
||||
exchange_name='bitfinex',
|
||||
algo_namespace='buy_and_hodl',
|
||||
base_currency='usd',
|
||||
start=pd.to_datetime('2017-11-01', utc=True),
|
||||
end=pd.to_datetime('2017-11-10', utc=True),
|
||||
)
|
||||
|
||||
@@ -132,7 +132,7 @@ class Exchange:
|
||||
|
||||
def get_symbol(self, asset):
|
||||
"""
|
||||
The the exchange specific symbol of the specified market.
|
||||
The exchange specific symbol of the specified market.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -203,10 +203,12 @@ class Exchange:
|
||||
assets = self.assets if not is_local else self.local_assets
|
||||
|
||||
for key in assets:
|
||||
if not asset and assets[key].symbol.lower() == symbol.lower() and (
|
||||
not data_frequency or (
|
||||
data_frequency == 'minute' and assets[
|
||||
key].end_minute is not None)):
|
||||
has_data = (data_frequency == 'minute'
|
||||
and assets[key].end_minute is not None) \
|
||||
or (data_frequency == 'daily'
|
||||
and assets[key].end_daily is not None)
|
||||
if not asset and assets[key].symbol.lower() == symbol.lower() \
|
||||
and (not data_frequency or has_data):
|
||||
asset = assets[key]
|
||||
|
||||
return asset
|
||||
@@ -226,18 +228,19 @@ class Exchange:
|
||||
"""
|
||||
asset = None
|
||||
|
||||
log.debug('searching asset {} on the server')
|
||||
log.debug('searching asset {} on the server'.format(symbol))
|
||||
asset = self._find_asset(asset, symbol, data_frequency, False)
|
||||
|
||||
log.debug('asset {} not found on the server, searching local assets')
|
||||
log.debug('asset {} not found on the server, searching local '
|
||||
'assets'.format(symbol))
|
||||
asset = self._find_asset(asset, symbol, data_frequency, True)
|
||||
|
||||
if not asset:
|
||||
all_values = list(self.assets.values()) + \
|
||||
list(self.local_assets.values())
|
||||
supported_symbols = [
|
||||
supported_symbols = sorted([
|
||||
asset.symbol for asset in all_values
|
||||
]
|
||||
])
|
||||
|
||||
raise SymbolNotFoundOnExchange(
|
||||
symbol=symbol,
|
||||
|
||||
@@ -159,13 +159,17 @@ You can now test your algorithm using cryptoassets' historical pricing data,
|
||||
``catalyst`` provides three interfaces:
|
||||
|
||||
- A command-line interface (CLI),
|
||||
- the ``IPython Notebook`` magic,
|
||||
- and a :func:`~catalyst.run_algorithm` that you can call from other
|
||||
Python scripts.
|
||||
- a :func:`~catalyst.run_algorithm()` that you can call from other
|
||||
Python scripts,
|
||||
- and the ``Jupyter Notebook`` magic.
|
||||
|
||||
We'll start with the CLI, and introduce the ``IPython Notebook`` below. Some of
|
||||
the :doc:`example algorithms <example-algos>` provide instructions on how to run
|
||||
them both from the CLI, and using the :func:`~catalyst.run_algorithm` function.
|
||||
|
||||
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>`
|
||||
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
|
||||
corresponding section on :doc:`Catalyst & Jupyter Notebook <jupyter>` after you
|
||||
have assimilated the contents of this tutorial.
|
||||
|
||||
Command line interface
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -263,7 +267,7 @@ command line args all the time.
|
||||
Thus, to execute our algorithm from above and save the results to
|
||||
``buy_btc_simple_out.pickle`` we would call ``catalyst run`` as follows:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: bash
|
||||
|
||||
catalyst run -f buy_btc_simple.py -x bitfinex --start 2016-1-1 --end 2017-9-30 -c usd --capital-base 100000 -o buy_btc_simple_out.pickle
|
||||
|
||||
@@ -560,78 +564,235 @@ If the short-mavg crosses from above we exit the positions as we assume
|
||||
the stock to go down further.
|
||||
|
||||
As we need to have access to previous prices to implement this strategy
|
||||
we need a new concept: History
|
||||
we need a new concept: History. ``data.history()`` is a convenience function
|
||||
that keeps a rolling window of data for you. The first argument is the number
|
||||
of bars you want to collect, the second argument is the unit (either ``'1d'``
|
||||
for daily or ``'1m'`` for minute frequency, but note that you need to have
|
||||
minute-level data when using ``1m``). This is a function we use in the
|
||||
``handle_data()`` section.
|
||||
|
||||
``data.history()`` is a convenience function that keeps a rolling window of
|
||||
data for you. The first argument is the number of bars you want to
|
||||
collect, the second argument is the unit (either ``'1d'`` for ``'1m'``
|
||||
but note that you need to have minute-level data for using ``1m``). This is
|
||||
a function we use in the ``handle_data()`` section:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
%load_ext catalyst
|
||||
You will note that the code below is substantially longer than the previous
|
||||
examples. Don't get overwhelmed by it as the logic is fairly simple and easy to
|
||||
follow. Most of the added some complexity has been added to beautify the output,
|
||||
which you can skim through for now. A copy of this algorithm is available in
|
||||
the ``examples`` directory:
|
||||
`dual_moving_average.py <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/dual_moving_average.py>`_.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
%%catalyst --start 2016-4-1 --end 2017-9-30 -x bitfinex
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from logbook import Logger
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from catalyst.api import order, record, symbol, order_target
|
||||
from catalyst import run_algorithm
|
||||
from catalyst.api import (order, record, symbol, order_target_percent,
|
||||
get_open_orders)
|
||||
from catalyst.exchange.stats_utils import extract_transactions
|
||||
|
||||
NAMESPACE = 'dual_moving_average'
|
||||
log = Logger(NAMESPACE)
|
||||
|
||||
def initialize(context):
|
||||
context.i = 0
|
||||
context.asset = symbol('btc_usd')
|
||||
context.i = 0
|
||||
context.asset = symbol('ltc_usd')
|
||||
context.base_price = None
|
||||
|
||||
|
||||
def handle_data(context, data):
|
||||
# Skip first 150 days to get full windows
|
||||
context.i += 1
|
||||
if context.i < 150:
|
||||
# define the windows for the moving averages
|
||||
short_window = 50
|
||||
long_window = 200
|
||||
|
||||
# Skip as many bars as long_window to properly compute the average
|
||||
context.i += 1
|
||||
if context.i < long_window:
|
||||
return
|
||||
|
||||
# Compute averages
|
||||
# data.history() has to be called with the same params
|
||||
# from above and returns a pandas dataframe.
|
||||
short_mavg = data.history(context.asset, 'price', bar_count=50, frequency="1d").mean()
|
||||
long_mavg = data.history(context.asset, 'price', bar_count=150, frequency="1d").mean()
|
||||
# Compute moving averages calling data.history() for each
|
||||
# moving average with the appropriate parameters. We choose to use
|
||||
# minute bars for this simulation -> freq="1m"
|
||||
# Returns a pandas dataframe.
|
||||
short_mavg = data.history(context.asset, 'price',
|
||||
bar_count=short_window, frequency="1m").mean()
|
||||
long_mavg = data.history(context.asset, 'price',
|
||||
bar_count=long_window, frequency="1m").mean()
|
||||
|
||||
# Trading logic
|
||||
if short_mavg > long_mavg:
|
||||
# order_target orders as many shares as needed to
|
||||
# achieve the desired number of shares.
|
||||
order_target(context.asset, 100)
|
||||
elif short_mavg < long_mavg:
|
||||
order_target(context.asset, 0)
|
||||
# Let's keep the price of our asset in a more handy variable
|
||||
price = data.current(context.asset, 'price')
|
||||
|
||||
# If base_price is not set, we use the current value. This is the
|
||||
# price at the first bar which we reference to calculate price_change.
|
||||
if context.base_price is None:
|
||||
context.base_price = price
|
||||
price_change = (price - context.base_price) / context.base_price
|
||||
|
||||
# Save values for later inspection
|
||||
record(price=price,
|
||||
cash=context.portfolio.cash,
|
||||
price_change=price_change,
|
||||
short_mavg=short_mavg,
|
||||
long_mavg=long_mavg)
|
||||
|
||||
# Since we are using limit orders, some orders may not execute immediately
|
||||
# we wait until all orders are executed before considering more trades.
|
||||
orders = get_open_orders(context.asset)
|
||||
if len(orders) > 0:
|
||||
return
|
||||
|
||||
# Exit if we cannot trade
|
||||
if not data.can_trade(context.asset):
|
||||
return
|
||||
|
||||
# We check what's our position on our portfolio and trade accordingly
|
||||
pos_amount = context.portfolio.positions[context.asset].amount
|
||||
|
||||
# Trading logic
|
||||
if short_mavg > long_mavg and pos_amount == 0:
|
||||
# we buy 100% of our portfolio for this asset
|
||||
order_target_percent(context.asset, 1)
|
||||
elif short_mavg < long_mavg and pos_amount > 0:
|
||||
# we sell all our positions for this asset
|
||||
order_target_percent(context.asset, 0)
|
||||
|
||||
# Save values for later inspection
|
||||
record(btc=data.current(context.asset, 'price'),
|
||||
short_mavg=short_mavg,
|
||||
long_mavg=long_mavg)
|
||||
|
||||
def analyze(context, perf):
|
||||
import matplotlib.pyplot as plt
|
||||
fig = plt.figure(figsize=(12,12))
|
||||
ax1 = fig.add_subplot(211)
|
||||
perf.portfolio_value.plot(ax=ax1)
|
||||
ax1.set_ylabel('portfolio value in $')
|
||||
|
||||
ax2 = fig.add_subplot(212)
|
||||
perf['btc'].plot(ax=ax2)
|
||||
perf[['short_mavg', 'long_mavg']].plot(ax=ax2)
|
||||
# Get the base_currency that was passed as a parameter to the simulation
|
||||
base_currency = context.exchanges.values()[0].base_currency.upper()
|
||||
|
||||
perf_trans = perf.ix[[t != [] for t in perf.transactions]]
|
||||
buys = perf_trans.ix[[t[0]['amount'] > 0 for t in perf_trans.transactions]]
|
||||
sells = perf_trans.ix[
|
||||
[t[0]['amount'] < 0 for t in perf_trans.transactions]]
|
||||
ax2.plot(buys.index, perf.short_mavg.ix[buys.index],
|
||||
'^', markersize=10, color='m')
|
||||
ax2.plot(sells.index, perf.short_mavg.ix[sells.index],
|
||||
'v', markersize=10, color='k')
|
||||
ax2.set_ylabel('price in $')
|
||||
plt.legend(loc=0)
|
||||
plt.show()
|
||||
# First chart: Plot portfolio value using base_currency
|
||||
ax1 = plt.subplot(411)
|
||||
perf.loc[:, ['portfolio_value']].plot(ax=ax1)
|
||||
ax1.legend_.remove()
|
||||
ax1.set_ylabel('Portfolio Value\n({})'.format(base_currency))
|
||||
start, end = ax1.get_ylim()
|
||||
ax1.yaxis.set_ticks(np.arange(start, end, (end-start)/5))
|
||||
|
||||
Here we are explicitly defining an ``analyze()`` function that gets
|
||||
automatically called once the backtest is done.
|
||||
# Second chart: Plot asset price, moving averages and buys/sells
|
||||
ax2 = plt.subplot(412, sharex=ax1)
|
||||
perf.loc[:, ['price','short_mavg','long_mavg']].plot(ax=ax2, label='Price')
|
||||
ax2.legend_.remove()
|
||||
ax2.set_ylabel('{asset}\n({base})'.format(
|
||||
asset = context.asset.symbol,
|
||||
base = base_currency
|
||||
))
|
||||
start, end = ax2.get_ylim()
|
||||
ax2.yaxis.set_ticks(np.arange(start, end, (end-start)/5))
|
||||
|
||||
transaction_df = extract_transactions(perf)
|
||||
if not transaction_df.empty:
|
||||
buy_df = transaction_df[transaction_df['amount'] > 0]
|
||||
sell_df = transaction_df[transaction_df['amount'] < 0]
|
||||
ax2.scatter(
|
||||
buy_df.index.to_pydatetime(),
|
||||
perf.loc[buy_df.index, 'price'],
|
||||
marker='^',
|
||||
s=100,
|
||||
c='green',
|
||||
label=''
|
||||
)
|
||||
ax2.scatter(
|
||||
sell_df.index.to_pydatetime(),
|
||||
perf.loc[sell_df.index, 'price'],
|
||||
marker='v',
|
||||
s=100,
|
||||
c='red',
|
||||
label=''
|
||||
)
|
||||
|
||||
# Third chart: Compare percentage change between our portfolio
|
||||
# and the price of the asset
|
||||
ax3 = plt.subplot(413, sharex=ax1)
|
||||
perf.loc[:, ['algorithm_period_return', 'price_change']].plot(ax=ax3)
|
||||
ax3.legend_.remove()
|
||||
ax3.set_ylabel('Percent Change')
|
||||
start, end = ax3.get_ylim()
|
||||
ax3.yaxis.set_ticks(np.arange(start, end, (end-start)/5))
|
||||
|
||||
# Fourth chart: Plot our cash
|
||||
ax4 = plt.subplot(414, sharex=ax1)
|
||||
perf.cash.plot(ax=ax4)
|
||||
ax4.set_ylabel('Cash\n({})'.format(base_currency))
|
||||
start, end = ax4.get_ylim()
|
||||
ax4.yaxis.set_ticks(np.arange(0, end, end/5))
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
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),
|
||||
)
|
||||
|
||||
In order to run the code above, you have to ingest the needed data first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
catalyst ingest-exchange -x bitfinex -f minute -i ltc_usd
|
||||
|
||||
And then run the code above with the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
catalyst run -f dual_moving_average.py -x bitfinex -s 2017-9-22 -e 2017-9-23 --capital-base 1000 --base-currency usd --data-frequency minute -o out.pickle
|
||||
|
||||
Alternatively, we can make use of the ``run_algorithm()`` function included at
|
||||
the end of the file, where we can specify all the simulation parameters, and
|
||||
execute this file as a Python script:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python dual_moving_average.py
|
||||
|
||||
Either way, we obtain the following charts:
|
||||
|
||||
.. image:: https://s3.amazonaws.com/enigmaco-docs/github.io/tutorial_dual_moving_average.png
|
||||
|
||||
|
||||
A few comments on the code above:
|
||||
|
||||
At the beginning of our code, we import a number of Python libraries that we
|
||||
will be using in different parts of our script. It's good practice to keep all
|
||||
imports at the beginning of the file, as they are available globally
|
||||
throughout our script. All the libraries imported in this example are already
|
||||
present in your environment since they are prerequisites for the Catalyst
|
||||
installation.
|
||||
|
||||
Focus on the code that is inside ``handle_data()`` that is where all the
|
||||
trading logic occurs. You can safely dismiss most of the code in the
|
||||
``analyze()`` section, which is mostly to customize the visualization of the
|
||||
performance of our algorithm using the matplotlib library. You can copy and
|
||||
paste this whole section into other algorithms to obtain a similar display.
|
||||
|
||||
Inside the ``handle_data()``, we also used the ``order_target_percent()``
|
||||
function above. This and other functions like it can make order management
|
||||
and portfolio rebalancing much easier.
|
||||
|
||||
The ``ltc_usd`` asset was arbitrarily chosen. The values of 50 and 200 for the
|
||||
``short_window`` and ``long_window`` parameters are fairly common for a dual
|
||||
moving average crossover strategy from the world of traditional stocks (but
|
||||
bear in mind that they are usually used with daily bars instead of minute
|
||||
bars). The ``start`` and ``end`` dates have been chosen so as to demonstrate
|
||||
how our strategy can both perform better (blue line above green line on the
|
||||
``Percent Change`` chart) and worse (green line above blue line towards the end) than the
|
||||
price of the asset we are trading.
|
||||
|
||||
You can change any of these parameters: ``asset``, ``short_window``,
|
||||
``long_window``, ``start_date`` and ``end_date`` and compare the results, and
|
||||
you will see that in most cases, the performance is either worse than the
|
||||
price of the asset, or you are overfitting to one specific case. As we said
|
||||
at the beginning of this section, this strategy is probably not used by any
|
||||
serious trader anymore, but its educational purpose.
|
||||
|
||||
Although it might not be directly apparent, the power of ``history()``
|
||||
(pun intended) can not be under-estimated as most algorithms make use of
|
||||
@@ -643,21 +804,13 @@ the ``scikit-learn`` functions require ``numpy.ndarray``\ s rather than
|
||||
``pandas.DataFrame``\ s, so you can simply pass the underlying
|
||||
``ndarray`` of a ``DataFrame`` via ``.values``).
|
||||
|
||||
We also used the ``order_target()`` function above. This and other
|
||||
functions like it can make order management and portfolio rebalancing
|
||||
much easier.
|
||||
|
||||
|
||||
Conclusions
|
||||
~~~~~~~~~~~
|
||||
Next steps
|
||||
~~~~~~~~~~
|
||||
|
||||
We hope that this tutorial gave you a little insight into the
|
||||
architecture, API, and features of ``catalyst``. For next steps, check
|
||||
out some of the
|
||||
`examples <https://github.com/enigmampc/catalyst/tree/master/catalyst/examples>`__.
|
||||
The natural next step would be too look into the
|
||||
`buy_and_hodl <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/buy_and_hodl.py>`_
|
||||
example, which is a more elaborated and realistic version of the ``buy_btc_simple`` example presented in this tutorial.
|
||||
architecture, API, and features of Catalyst. For next steps, check
|
||||
out some of the other :doc:`example algorithms<example-algos>`.
|
||||
|
||||
Feel free to ask questions on the ``#catalyst_dev`` channel of our
|
||||
`Discord group <https://discord.gg/SJK32GY>`__ and report
|
||||
|
||||
+34
-26
@@ -2,9 +2,18 @@
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
Version 0.3.10
|
||||
^^^^^^^^^^^^^
|
||||
**Release Date**: 2017-11-28
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Fixed issue with fetching assets with daily frequency
|
||||
|
||||
Version 0.3.9
|
||||
^^^^^^^^^^^^^
|
||||
**Release Date**: 2017-11-14
|
||||
**Release Date**: 2017-11-28
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
@@ -76,7 +85,7 @@ Bug Fixes
|
||||
- Fixed issue with sell orders in backtesting
|
||||
- Fixed data frequency issues with data.history() in backtesting
|
||||
- Fixed an issue with can_trade()
|
||||
- Reduced the commission and slippage values to account for lower volume
|
||||
- Reduced the commission and slippage values to account for lower volume
|
||||
transactions
|
||||
|
||||
Build
|
||||
@@ -88,17 +97,17 @@ Documentation
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
- Improved installation notes for Windows C++ compiler and Conda
|
||||
- Addition of
|
||||
- Addition of
|
||||
`Jupyter Notebook guide <https://enigmampc.github.io/catalyst/jupyter.html>`_
|
||||
- Addition of
|
||||
- Addition of
|
||||
`Live Trading page <https://enigmampc.github.io/catalyst/live-trading.html>`_
|
||||
- Addition of
|
||||
- Addition of
|
||||
`Videos page <https://enigmampc.github.io/catalyst/videos.html>`_
|
||||
- Addition of
|
||||
- Addition of
|
||||
`Resources page <https://enigmampc.github.io/catalyst/resources.html>`_
|
||||
- Addition of `Development Guidelines
|
||||
- Addition of `Development Guidelines
|
||||
<https://enigmampc.github.io/catalyst/development-guidelines.html>`_
|
||||
- Addition of
|
||||
- Addition of
|
||||
`Release Notes <https://enigmampc.github.io/catalyst/releases.html>`_
|
||||
- Updated code docstrings
|
||||
|
||||
@@ -149,10 +158,10 @@ Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Fixed OS-dependent path issue in data bundle
|
||||
- Changed handling of empty ``auth.json``, instead of throwing an error for
|
||||
- Changed handling of empty ``auth.json``, instead of throwing an error for
|
||||
missing file
|
||||
- Updated ``etc/python2.7-environment.yml`` to work with Catalyst version 0.3
|
||||
- Updated ``catalyst/examples/buy_and_hodl.py`` and
|
||||
- Updated ``catalyst/examples/buy_and_hodl.py`` and
|
||||
``catalyst/examples/buy_low_sell_high.py`` to work with Catalyst version 0.3
|
||||
|
||||
|
||||
@@ -172,18 +181,18 @@ Version 0.2.dev5
|
||||
^^^^^^^^^^^^^^^^
|
||||
**Release Date**: 2017-10-03
|
||||
|
||||
- Fixes bug in data.history function that was formatting 'volume' data as
|
||||
integers, now they are returned as floats with up to 9 decimals of precision.
|
||||
- Fixes bug in data.history function that was formatting 'volume' data as
|
||||
integers, now they are returned as floats with up to 9 decimals of precision.
|
||||
Data bundles redone.
|
||||
|
||||
Version 0.2.dev4
|
||||
Version 0.2.dev4
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
**Release Date**: 2017-09-20
|
||||
|
||||
- Fixes bug in the pricing resolution of 1-minute data, now set to 8 decimal
|
||||
- Fixes bug in the pricing resolution of 1-minute data, now set to 8 decimal
|
||||
places. Pricing resolution of daily data remains set to 9 decimal places.
|
||||
- The current data bundle takes 340MB compressed for download, and 460MB
|
||||
- The current data bundle takes 340MB compressed for download, and 460MB
|
||||
uncompressed on disk for Catalyst to use.
|
||||
|
||||
Version 0.2.dev3
|
||||
@@ -193,14 +202,14 @@ Version 0.2.dev3
|
||||
|
||||
- 1-minute resolution OHLCV data bundle for backtesting from Poloniex exchange
|
||||
- Implementation of trading of fractional crypto assets (i.e. 0.01 BTC)
|
||||
- Minimum trade size of a coin can be configured on a per-coin basis, defaults
|
||||
to 0.00000001 in backtesting (most exchanges set the minimum trade to larger
|
||||
- Minimum trade size of a coin can be configured on a per-coin basis, defaults
|
||||
to 0.00000001 in backtesting (most exchanges set the minimum trade to larger
|
||||
amounts, which will impact live trading)
|
||||
- Increased pricing resolution from 3 to 9 decimal places
|
||||
- The current data bundle takes 40MB compressed for download, and 99MB
|
||||
- The current data bundle takes 40MB compressed for download, and 99MB
|
||||
uncompressed on disk for Catalyst to use.
|
||||
|
||||
Version 0.2.dev2
|
||||
Version 0.2.dev2
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
**Release Date**: 2017-09-07
|
||||
@@ -216,15 +225,15 @@ Version 0.2.dev1
|
||||
|
||||
- Comprehensive trading functionality against exchanges Bitfinex and Bittrex.
|
||||
- Support for all trading pairs available on each exchange.
|
||||
- Multiple algorithms can trade simultaneously against a single exchange
|
||||
- Multiple algorithms can trade simultaneously against a single exchange
|
||||
using the same account.
|
||||
- Each algorithm has a persisted state (i.e. algorithm can be stopped and
|
||||
restarted preserving the state without data loss) that tracks all open
|
||||
- Each algorithm has a persisted state (i.e. algorithm can be stopped and
|
||||
restarted preserving the state without data loss) that tracks all open
|
||||
orders, executed transactions and portfolio positions.
|
||||
|
||||
- Minute by minute portfolio performance metrics.
|
||||
|
||||
- Daily summary performance statistics compatible with pyfolio, a Python
|
||||
- Daily summary performance statistics compatible with pyfolio, a Python
|
||||
library for performance and risk analysis of financial portfolios
|
||||
|
||||
Version 0.1.dev9
|
||||
@@ -232,13 +241,13 @@ Version 0.1.dev9
|
||||
|
||||
**Release Date**: 2017-08-28
|
||||
|
||||
- Retrieval of crypto benchmark from bundle, instead of hitting Poloniex
|
||||
- Retrieval of crypto benchmark from bundle, instead of hitting Poloniex
|
||||
exchange directly
|
||||
- Change of bundle storage provider from Dropbox to AWS
|
||||
- Fix issue with 1/1000 scaling issue of prices in bundle
|
||||
|
||||
Version 0.1.dev8
|
||||
^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
**Release Date**: 2017-08-18
|
||||
|
||||
@@ -258,4 +267,3 @@ Version 0.1.dev6
|
||||
**Release Date**: 2017-07-13
|
||||
|
||||
- Initial public release
|
||||
|
||||
|
||||
Reference in New Issue
Block a user