Compare commits

..
16 Commits
Author SHA1 Message Date
Victor Grau Serrat 3399e22ea2 MAINT: [0.3.10] updated generate_symbols_json 2018-03-22 10:28:01 -06:00
Victor Grau Serrat 79e5dec813 BUG: minor fix in Poloniex curate script 2018-01-04 14:18:27 +00:00
fredfortier 803823eac0 merging from develop 2017-11-28 01:41:58 -05:00
fredfortier 5a18e09730 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	docs/source/releases.rst
2017-11-28 01:34:38 -05:00
fredfortier dd41f8c006 BUG: fixed issue with daily frequency 2017-11-28 01:34:17 -05:00
Victor Grau Serrat 7a2a4817fe BUG: missing parameters in log statements 2017-11-27 23:11:22 -07:00
Victor Grau Serrat 105522e5ab DOC: fixed date from 0.3.9 release 2017-11-27 22:01:19 -07:00
Victor Grau Serrat a52e201f86 DOC: improved dual_moving_average.py example algo 2017-11-27 21:10:17 -07:00
Victor Grau Serrat 697ff54125 Merge branch 'develop' of github.com:enigmampc/catalyst into develop 2017-11-27 21:07:15 -07:00
Victor Grau Serrat 4bcd34bd78 DOC: improved beginner tutorial 2017-11-27 21:07:03 -07:00
fredfortier 64c52c7a3c BUG: fixed issue #72 with the buy_and_hodl sample algo 2017-11-27 18:44:50 -05:00
fredfortier 1c143eb9ea DOC: 0.3.9 release notes 2017-11-27 17:55:56 -05:00
fredfortier 1da4ccfb8c Merge remote-tracking branch 'origin/master' 2017-11-27 17:55:32 -05:00
fredfortier a61b22b821 DOC: 0.3.9 release notes 2017-11-27 17:55:22 -05:00
fredfortier d07e0edd88 DOC: 0.3.9 release notes 2017-11-27 17:54:34 -05:00
Victor Grau Serrat c2821ab77b DOC: added example_algo: Dual Moving Average Crossover 2017-11-27 15:43:57 -07:00
7 changed files with 473 additions and 121 deletions
+2 -1
View File
@@ -182,7 +182,8 @@ class PoloniexCurator(object):
for this currencyPair for this currencyPair
''' '''
try: try:
if( 'end_file' in locals() and end_file + 3600 < end): if(temp is not None
or ('end_file' in locals() and end_file + 3600 < end)):
if (temp is None): if (temp is None):
temp = os.tmpfile() temp = os.tmpfile()
tempcsv = csv.writer(temp) tempcsv = csv.writer(temp)
+23 -6
View File
@@ -16,6 +16,7 @@
# limitations under the License. # limitations under the License.
import pandas as pd import pandas as pd
from catalyst import run_algorithm
from catalyst.api import ( from catalyst.api import (
order_target_value, order_target_value,
symbol, symbol,
@@ -26,7 +27,7 @@ from catalyst.api import (
def initialize(context): def initialize(context):
context.ASSET_NAME = 'btc_usdt' context.ASSET_NAME = 'btc_usd'
context.TARGET_HODL_RATIO = 0.8 context.TARGET_HODL_RATIO = 0.8
context.RESERVE_RATIO = 1.0 - context.TARGET_HODL_RATIO 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 # Check if still buying and could (approximately) afford another purchase
if context.is_buying and cash > price: if context.is_buying and cash > price:
print('buying')
# Place order to make position in asset equal to target_hodl_value # Place order to make position in asset equal to target_hodl_value
order_target_value( order_target_value(
context.asset, context.asset,
@@ -91,12 +93,13 @@ def analyze(context=None, results=None):
buys = trans.ix[ buys = trans.ix[
[t[0]['amount'] > 0 for t in trans.transactions] [t[0]['amount'] > 0 for t in trans.transactions]
] ]
ax2.plot( ax2.scatter(
buys.index, buys.index.to_pydatetime(),
results.price[buys.index], results.price[buys.index],
'^', marker='^',
markersize=10, s=100,
color='g', c='g',
label=''
) )
ax3 = plt.subplot(613, sharex=ax1) ax3 = plt.subplot(613, sharex=ax1)
@@ -135,3 +138,17 @@ def analyze(context=None, results=None):
plt.gcf().set_size_inches(18, 8) plt.gcf().set_size_inches(18, 8)
plt.show() 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),
)
+153
View File
@@ -0,0 +1,153 @@
import numpy as np
import pandas as pd
from logbook import Logger
import matplotlib.pyplot as plt
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('ltc_usd')
context.base_price = None
def handle_data(context, data):
# 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 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()
# 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)
def analyze(context, perf):
# Get the base_currency that was passed as a parameter to the simulation
base_currency = context.exchanges.values()[0].base_currency.upper()
# 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))
# 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),
)
+6 -6
View File
@@ -63,7 +63,7 @@ class Bitfinex(Exchange):
# Max is 90 but playing it safe # Max is 90 but playing it safe
# https://www.bitfinex.com/posts/188 # https://www.bitfinex.com/posts/188
self.max_requests_per_minute = 80 self.max_requests_per_minute = 9
self.request_cpt = dict() self.request_cpt = dict()
self.bundle = ExchangeBundle(self.name) self.bundle = ExchangeBundle(self.name)
@@ -586,10 +586,9 @@ class Bitfinex(Exchange):
def generate_symbols_json(self, filename=None, source_dates=False): def generate_symbols_json(self, filename=None, source_dates=False):
symbol_map = {} symbol_map = {}
if not source_dates: fn, r = download_exchange_symbols(self.name)
fn, r = download_exchange_symbols(self.name) with open(fn) as data_file:
with open(fn) as data_file: cached_symbols = json.load(data_file)
cached_symbols = json.load(data_file)
response = self._request('symbols', None) response = self._request('symbols', None)
@@ -643,6 +642,7 @@ class Bitfinex(Exchange):
try: try:
self.ask_request() self.ask_request()
time.sleep(60 / self.max_requests_per_minute)
response = requests.get(url) response = requests.get(url)
except Exception as e: except Exception as e:
raise ExchangeRequestError(error=e) raise ExchangeRequestError(error=e)
@@ -654,7 +654,7 @@ class Bitfinex(Exchange):
+/- 31 days +/- 31 days
""" """
if (len(response.json())): if (len(response.json())):
startmonth = response.json()[-1][0] startmonth = int(response.json()[-1][0])
else: else:
startmonth = int((time.time() - 15 * 24 * 3600) * 1000) startmonth = int((time.time() - 15 * 24 * 3600) * 1000)
+12 -9
View File
@@ -132,7 +132,7 @@ class Exchange:
def get_symbol(self, asset): def get_symbol(self, asset):
""" """
The the exchange specific symbol of the specified market. The exchange specific symbol of the specified market.
Parameters Parameters
---------- ----------
@@ -203,10 +203,12 @@ class Exchange:
assets = self.assets if not is_local else self.local_assets assets = self.assets if not is_local else self.local_assets
for key in assets: for key in assets:
if not asset and assets[key].symbol.lower() == symbol.lower() and ( has_data = (data_frequency == 'minute'
not data_frequency or ( and assets[key].end_minute is not None) \
data_frequency == 'minute' and assets[ or (data_frequency == 'daily'
key].end_minute is not None)): 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] asset = assets[key]
return asset return asset
@@ -226,18 +228,19 @@ class Exchange:
""" """
asset = None 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) 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) asset = self._find_asset(asset, symbol, data_frequency, True)
if not asset: if not asset:
all_values = list(self.assets.values()) + \ all_values = list(self.assets.values()) + \
list(self.local_assets.values()) list(self.local_assets.values())
supported_symbols = [ supported_symbols = sorted([
asset.symbol for asset in all_values asset.symbol for asset in all_values
] ])
raise SymbolNotFoundOnExchange( raise SymbolNotFoundOnExchange(
symbol=symbol, symbol=symbol,
+225 -72
View File
@@ -159,13 +159,17 @@ You can now test your algorithm using cryptoassets' historical pricing data,
``catalyst`` provides three interfaces: ``catalyst`` provides three interfaces:
- A command-line interface (CLI), - A command-line interface (CLI),
- the ``IPython Notebook`` magic, - a :func:`~catalyst.run_algorithm()` that you can call from other
- and a :func:`~catalyst.run_algorithm` that you can call from other Python scripts,
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 We'll start with the CLI, and introduce the ``run_algorithm()`` in the last
them both from the CLI, and using the :func:`~catalyst.run_algorithm` function. 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 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 Thus, to execute our algorithm from above and save the results to
``buy_btc_simple_out.pickle`` we would call ``catalyst run`` as follows: ``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 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. the stock to go down further.
As we need to have access to previous prices to implement this strategy 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 You will note that the code below is substantially longer than the previous
data for you. The first argument is the number of bars you want to examples. Don't get overwhelmed by it as the logic is fairly simple and easy to
collect, the second argument is the unit (either ``'1d'`` for ``'1m'`` follow. Most of the added some complexity has been added to beautify the output,
but note that you need to have minute-level data for using ``1m``). This is which you can skim through for now. A copy of this algorithm is available in
a function we use in the ``handle_data()`` section: the ``examples`` directory:
`dual_moving_average.py <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/dual_moving_average.py>`_.
.. code-block:: python .. code-block:: python
%load_ext catalyst import numpy as np
import pandas as pd
from logbook import Logger
import matplotlib.pyplot as plt
.. code-block:: python 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
%%catalyst --start 2016-4-1 --end 2017-9-30 -x bitfinex NAMESPACE = 'dual_moving_average'
log = Logger(NAMESPACE)
from catalyst.api import order, record, symbol, order_target
def initialize(context): def initialize(context):
context.i = 0 context.i = 0
context.asset = symbol('btc_usd') context.asset = symbol('ltc_usd')
context.base_price = None
def handle_data(context, data): def handle_data(context, data):
# Skip first 150 days to get full windows # define the windows for the moving averages
context.i += 1 short_window = 50
if context.i < 150: long_window = 200
# Skip as many bars as long_window to properly compute the average
context.i += 1
if context.i < long_window:
return return
# Compute averages # Compute moving averages calling data.history() for each
# data.history() has to be called with the same params # moving average with the appropriate parameters. We choose to use
# from above and returns a pandas dataframe. # minute bars for this simulation -> freq="1m"
short_mavg = data.history(context.asset, 'price', bar_count=50, frequency="1d").mean() # Returns a pandas dataframe.
long_mavg = data.history(context.asset, 'price', bar_count=150, frequency="1d").mean() 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 # Let's keep the price of our asset in a more handy variable
if short_mavg > long_mavg: price = data.current(context.asset, 'price')
# order_target orders as many shares as needed to
# achieve the desired number of shares. # If base_price is not set, we use the current value. This is the
order_target(context.asset, 100) # price at the first bar which we reference to calculate price_change.
elif short_mavg < long_mavg: if context.base_price is None:
order_target(context.asset, 0) 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): 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) # Get the base_currency that was passed as a parameter to the simulation
perf['btc'].plot(ax=ax2) base_currency = context.exchanges.values()[0].base_currency.upper()
perf[['short_mavg', 'long_mavg']].plot(ax=ax2)
perf_trans = perf.ix[[t != [] for t in perf.transactions]] # First chart: Plot portfolio value using base_currency
buys = perf_trans.ix[[t[0]['amount'] > 0 for t in perf_trans.transactions]] ax1 = plt.subplot(411)
sells = perf_trans.ix[ perf.loc[:, ['portfolio_value']].plot(ax=ax1)
[t[0]['amount'] < 0 for t in perf_trans.transactions]] ax1.legend_.remove()
ax2.plot(buys.index, perf.short_mavg.ix[buys.index], ax1.set_ylabel('Portfolio Value\n({})'.format(base_currency))
'^', markersize=10, color='m') start, end = ax1.get_ylim()
ax2.plot(sells.index, perf.short_mavg.ix[sells.index], ax1.yaxis.set_ticks(np.arange(start, end, (end-start)/5))
'v', markersize=10, color='k')
ax2.set_ylabel('price in $')
plt.legend(loc=0)
plt.show()
Here we are explicitly defining an ``analyze()`` function that gets # Second chart: Plot asset price, moving averages and buys/sells
automatically called once the backtest is done. 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()`` Although it might not be directly apparent, the power of ``history()``
(pun intended) can not be under-estimated as most algorithms make use of (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 ``pandas.DataFrame``\ s, so you can simply pass the underlying
``ndarray`` of a ``DataFrame`` via ``.values``). ``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.
Next steps
Conclusions ~~~~~~~~~~
~~~~~~~~~~~
We hope that this tutorial gave you a little insight into the We hope that this tutorial gave you a little insight into the
architecture, API, and features of ``catalyst``. For next steps, check architecture, API, and features of Catalyst. For next steps, check
out some of the out some of the other :doc:`example algorithms<example-algos>`.
`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.
Feel free to ask questions on the ``#catalyst_dev`` channel of our Feel free to ask questions on the ``#catalyst_dev`` channel of our
`Discord group <https://discord.gg/SJK32GY>`__ and report `Discord group <https://discord.gg/SJK32GY>`__ and report
+26 -1
View File
@@ -2,6 +2,32 @@
Release Notes 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-28
Bug Fixes
~~~~~~~~~
- Fixed sortino warning issues (:issue:`77`)
- Adjusted computation of last candle of data.history (:issue:`71`)
Build
~~~~~
- Added capital_base parameter to live mode to limit cash (:issue:`79`)
- Added support for csv ingestion (:issue:`65`)
- Improved cash display in running stats (:issue:`80`)
Version 0.3.8 Version 0.3.8
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
**Release Date**: 2017-11-14 **Release Date**: 2017-11-14
@@ -241,4 +267,3 @@ Version 0.1.dev6
**Release Date**: 2017-07-13 **Release Date**: 2017-07-13
- Initial public release - Initial public release