diff --git a/catalyst/examples/buy_and_hodl.py b/catalyst/examples/buy_and_hodl.py index 536de1cd..74b04238 100644 --- a/catalyst/examples/buy_and_hodl.py +++ b/catalyst/examples/buy_and_hodl.py @@ -15,15 +15,11 @@ # See the License for the specific language governing permissions and # limitations under the License. import pandas as pd +import matplotlib.pyplot as plt from catalyst import run_algorithm -from catalyst.api import ( - order_target_value, - symbol, - record, - cancel_order, - get_open_orders, -) +from catalyst.api import (order_target_value, symbol, record, + cancel_order, get_open_orders, ) def initialize(context): @@ -78,15 +74,14 @@ def handle_data(context, data): def analyze(context=None, results=None): - import matplotlib.pyplot as plt # Plot the portfolio and asset data. ax1 = plt.subplot(611) results[['portfolio_value']].plot(ax=ax1) - ax1.set_ylabel('Portfolio Value (USD)') + ax1.set_ylabel('Portfolio\nValue\n(USD)') ax2 = plt.subplot(612, sharex=ax1) - ax2.set_ylabel('{asset} (USD)'.format(asset=context.ASSET_NAME)) + ax2.set_ylabel('{asset}\n(USD)'.format(asset=context.ASSET_NAME)) results[['price']].plot(ax=ax2) trans = results.ix[[t != [] for t in results.transactions]] @@ -126,11 +121,11 @@ def analyze(context=None, results=None): 'algorithm', 'benchmark', ]].plot(ax=ax5) - ax5.set_ylabel('Percent Change') + ax5.set_ylabel('Percent\nChange') ax6 = plt.subplot(616, sharex=ax1) results[['volume']].plot(ax=ax6) - ax6.set_ylabel('Volume (mCoins/5min)') + ax6.set_ylabel('Volume') plt.legend(loc=3) @@ -142,13 +137,13 @@ def analyze(context=None, results=None): if __name__ == '__main__': run_algorithm( capital_base=10000, - data_frequency='minute', + data_frequency='daily', 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), + start=pd.to_datetime('2015-03-01', utc=True), + end=pd.to_datetime('2017-10-31', utc=True), ) diff --git a/catalyst/examples/buy_btc_simple.py b/catalyst/examples/buy_btc_simple.py index ef64513b..5e4ebd57 100644 --- a/catalyst/examples/buy_btc_simple.py +++ b/catalyst/examples/buy_btc_simple.py @@ -3,7 +3,8 @@ https://enigmampc.github.io/catalyst/beginner-tutorial.html Run this example, by executing the following from your terminal: - catalyst run -f buy_btc_simple.py -x bitfinex --start 2016-1-1 --end 2017-9-30 -o buy_btc_simple_out.pickle + catalyst ingest-exchange -x bitfinex -f daily -i btc_usdt + catalyst run -f buy_btc_simple.py -x bitfinex --start 2016-1-1 --end 2017-9-30 -o buy_btc_simple_out.pickle If you want to run this code using another exchange, make sure that the asset is available on that exchange. For example, if you were to run @@ -12,7 +13,7 @@ context.asset = symbol('btc_usdt') # note 'usdt' instead of 'usd' and specify exchange poloniex as follows: - + catalyst ingest-exchange -x poloniex -f daily -i btc_usdt catalyst run -f buy_btc_simple.py -x poloniex --start 2016-1-1 --end 2017-9-30 -o buy_btc_simple_out.pickle To see which assets are available on each exchange, visit: diff --git a/catalyst/examples/dual_moving_average.py b/catalyst/examples/dual_moving_average.py new file mode 100644 index 00000000..a73461f1 --- /dev/null +++ b/catalyst/examples/dual_moving_average.py @@ -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), + ) \ No newline at end of file diff --git a/catalyst/examples/mean_reversion_simple.py b/catalyst/examples/mean_reversion_simple.py index 6d4922e1..75e9f2ea 100644 --- a/catalyst/examples/mean_reversion_simple.py +++ b/catalyst/examples/mean_reversion_simple.py @@ -248,7 +248,7 @@ if __name__ == '__main__': # catalyst run -f catalyst/examples/mean_reversion_simple.py -x poloniex -s 2017-10-1 -e 2017-11-10 -c usdt -n mean-reversion --data-frequency minute --capital-base 10000 run_algorithm( capital_base=10000, - data_frequency='minute', + data_frequency='daily', initialize=initialize, handle_data=handle_data, analyze=analyze, diff --git a/docs/source/releases.rst b/docs/source/releases.rst index ade535f7..1e968a57 100644 --- a/docs/source/releases.rst +++ b/docs/source/releases.rst @@ -85,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 @@ -97,17 +97,17 @@ Documentation ~~~~~~~~~~~~~ - Improved installation notes for Windows C++ compiler and Conda -- Addition of +- Addition of `Jupyter Notebook guide `_ -- Addition of +- Addition of `Live Trading page `_ -- Addition of +- Addition of `Videos page `_ -- Addition of +- Addition of `Resources page `_ -- Addition of `Development Guidelines +- Addition of `Development Guidelines `_ -- Addition of +- Addition of `Release Notes `_ - Updated code docstrings @@ -158,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 @@ -181,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 @@ -202,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 @@ -225,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 @@ -241,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 @@ -267,4 +267,3 @@ Version 0.1.dev6 **Release Date**: 2017-07-13 - Initial public release -