From 698b19c8fa2488bbd4a2b41b0960bd0eca17fc9f Mon Sep 17 00:00:00 2001 From: Victor Grau Serrat Date: Sun, 19 Nov 2017 23:51:57 -0700 Subject: [PATCH] DOC: updated examples/buy_and_hodl.py. Added Example Algos and Utilities pages to the documentation --- catalyst/examples/buy_and_hodl.py | 24 +---- docs/source/example-algos.rst | 172 ++++++++++++++++++++++++++++++ docs/source/index.rst | 2 + docs/source/utilities.rst | 149 ++++++++++++++++++++++++++ 4 files changed, 326 insertions(+), 21 deletions(-) create mode 100644 docs/source/example-algos.rst create mode 100644 docs/source/utilities.rst diff --git a/catalyst/examples/buy_and_hodl.py b/catalyst/examples/buy_and_hodl.py index e4146b3c..ef5b2a6f 100644 --- a/catalyst/examples/buy_and_hodl.py +++ b/catalyst/examples/buy_and_hodl.py @@ -16,7 +16,6 @@ # limitations under the License. import pandas as pd -from catalyst import run_algorithm from catalyst.api import ( order_target_value, symbol, @@ -27,15 +26,10 @@ from catalyst.api import ( def initialize(context): - context.ASSET_NAME = 'BTC_USDT' + context.ASSET_NAME = 'btc_usdt' context.TARGET_HODL_RATIO = 0.8 context.RESERVE_RATIO = 1.0 - context.TARGET_HODL_RATIO - # For all trading pairs in the poloniex bundle, the default denomination - # currently supported by Catalyst is 1/1000th of a full coin. Use this - # constant to scale the price of up to that of a full coin if desired. - context.TICK_SIZE = 1000.0 - context.is_buying = True context.asset = symbol(context.ASSET_NAME) @@ -91,7 +85,7 @@ def analyze(context=None, results=None): ax2 = plt.subplot(612, sharex=ax1) ax2.set_ylabel('{asset} (USD)'.format(asset=context.ASSET_NAME)) - (context.TICK_SIZE * results[['price']]).plot(ax=ax2) + results[['price']].plot(ax=ax2) trans = results.ix[[t != [] for t in results.transactions]] buys = trans.ix[ @@ -99,7 +93,7 @@ def analyze(context=None, results=None): ] ax2.plot( buys.index, - context.TICK_SIZE * results.price[buys.index], + results.price[buys.index], '^', markersize=10, color='g', @@ -141,15 +135,3 @@ def analyze(context=None, results=None): plt.gcf().set_size_inches(18, 8) plt.show() - -run_algorithm( - capital_base=10000, - data_frequency='minute', - initialize=initialize, - handle_data=handle_data, - analyze=analyze, - exchange_name='poloniex', - base_currency='usd', - start=pd.to_datetime('2017-10-1', utc=True), - end=pd.to_datetime('2017-11-10', utc=True), -) diff --git a/docs/source/example-algos.rst b/docs/source/example-algos.rst new file mode 100644 index 00000000..7882208d --- /dev/null +++ b/docs/source/example-algos.rst @@ -0,0 +1,172 @@ +| +Example Algorithms +================== + +This section documents a small number of example algorithms to complement the +beginner tutorial, and show how other trading algorithms can be implemented +using Catalyst: + +Buy and Hodl +~~~~~~~~~~~~ + +source: `examples/buy_and_hodl.py `_ + +First ingest the historical pricing data needed to run this algorithm: + +.. code-block:: bash + + catalyst ingest-exchange -x poloniex -f daily -i btc_usdt + +Then, you can run the code below with the following command: + +.. code-block:: bash + + catalyst run -f buy_and_hodl.py --start 2015-3-1 --end 2017-10-31 --capital-base 100000 -x poloniex -c btc -o bah.pickle + +This command will run the trading algorithm in the specified time range and +plot the resulting performance using the matplotlib library. You can choose any +date interval with the ``--start`` and ``--end`` parameters, but bear in mind +that 2015-3-1 is the earliest date that Catalyst supports (if you choose an +earlier date, you'll get an error), and the most recent date you can choose is +one day prior to the current date. + + +.. code-block:: python + + #!/usr/bin/env python + # + # Copyright 2017 Enigma MPC, Inc. + # Copyright 2015 Quantopian, Inc. + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + import pandas as pd + + from catalyst.api import ( + order_target_value, + symbol, + record, + cancel_order, + get_open_orders, + ) + + + def initialize(context): + context.ASSET_NAME = 'btc_usdt' + context.TARGET_HODL_RATIO = 0.8 + context.RESERVE_RATIO = 1.0 - context.TARGET_HODL_RATIO + + context.is_buying = True + context.asset = symbol(context.ASSET_NAME) + + context.i = 0 + + + def handle_data(context, data): + context.i += 1 + + starting_cash = context.portfolio.starting_cash + target_hodl_value = context.TARGET_HODL_RATIO * starting_cash + reserve_value = context.RESERVE_RATIO * starting_cash + + # Cancel any outstanding orders + orders = get_open_orders(context.asset) or [] + for order in orders: + cancel_order(order) + + # Stop buying after passing the reserve threshold + cash = context.portfolio.cash + if cash <= reserve_value: + context.is_buying = False + + # Retrieve current asset price from pricing data + price = data.current(context.asset, 'price') + + # Check if still buying and could (approximately) afford another purchase + if context.is_buying and cash > price: + # Place order to make position in asset equal to target_hodl_value + order_target_value( + context.asset, + target_hodl_value, + limit_price=price * 1.1, + stop_price=price * 0.9, + ) + + record( + price=price, + volume=data.current(context.asset, 'volume'), + cash=cash, + starting_cash=context.portfolio.starting_cash, + leverage=context.account.leverage, + ) + + + 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)') + + ax2 = plt.subplot(612, sharex=ax1) + ax2.set_ylabel('{asset} (USD)'.format(asset=context.ASSET_NAME)) + results[['price']].plot(ax=ax2) + + trans = results.ix[[t != [] for t in results.transactions]] + buys = trans.ix[ + [t[0]['amount'] > 0 for t in trans.transactions] + ] + ax2.plot( + buys.index, + results.price[buys.index], + '^', + markersize=10, + color='g', + ) + + ax3 = plt.subplot(613, sharex=ax1) + results[['leverage', 'alpha', 'beta']].plot(ax=ax3) + ax3.set_ylabel('Leverage ') + + ax4 = plt.subplot(614, sharex=ax1) + results[['starting_cash', 'cash']].plot(ax=ax4) + ax4.set_ylabel('Cash (USD)') + + results[[ + 'treasury', + 'algorithm', + 'benchmark', + ]] = results[[ + 'treasury_period_return', + 'algorithm_period_return', + 'benchmark_period_return', + ]] + + ax5 = plt.subplot(615, sharex=ax1) + results[[ + 'treasury', + 'algorithm', + 'benchmark', + ]].plot(ax=ax5) + ax5.set_ylabel('Percent Change') + + ax6 = plt.subplot(616, sharex=ax1) + results[['volume']].plot(ax=ax6) + ax6.set_ylabel('Volume (mCoins/5min)') + + plt.legend(loc=3) + + # Show the plot. + plt.gcf().set_size_inches(18, 8) + plt.show() + diff --git a/docs/source/index.rst b/docs/source/index.rst index 82bbbd37..a0e8f097 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,6 +12,8 @@ Table of Contents jupyter live-trading naming-convention + example-algos + utilities videos resources development-guidelines diff --git a/docs/source/utilities.rst b/docs/source/utilities.rst new file mode 100644 index 00000000..8c89aa52 --- /dev/null +++ b/docs/source/utilities.rst @@ -0,0 +1,149 @@ +Utilities +========= + +This section covers a variety of utilites that provide complimentary +functionality to your trading algorithms. These are code snippets that you can +add to any algorithm to add the desired functionality. + +If you are looking for example trading algorithms, see the corresponding section. + +Output to CSV file +~~~~~~~~~~~~~~~~~~ + +Add this script to the analyze method to create and save a CSV file with the +results from the trading algorithm. This file will include the default +parameters of the results DataFrame plus any recorded variables and will be +saved in the same location where your trading algorithm is saved. The exact +script that you need to use depends on the interface that you are using to run +your trading algorithm, which could be the CLI or a Python Interpreter. + +1. Script to use with CLI: + + .. code-block:: python + + def analyze(context=None, results=None): + import sys + import os + from os.path import basename + + # Save results in CSV file + filename = os.path.splitext(basename(sys.argv[3]))[0] + results.to_csv(filename + '.csv') + +2. Script to use with Python Interpreter: + + .. code-block:: python + + def analyze(context=None, results=None): + import os + from os.path import basename + + # Save results in CSV file + filename = os.path.splitext(os.path.basename(__file__))[0] + results.to_csv(filename + '.csv') + +Extracting market data +~~~~~~~~~~~~~~~~~~~~~~ + +Use this script to save the price and volume data of one cryptoasset in a CSV +file, which will be saved in the same location and with the same name as your +Python file. To get custom data, simply modify the asset's symbol and the dates. +Run this script directly from your development environment: python scriptname.py, +where the contents of 'scriptname.py' are as follows. Two different version are +provided as an example for daily- and minute-resolution data respectively: + +Simpler case for daily data + +.. code-block:: python + + import os + import pytz + from datetime import datetime + + from catalyst.api import record, symbol, symbols + from catalyst.utils.run_algo import run_algorithm + + def initialize(context): + # Portfolio assets list + context.asset = symbol('btc_usdt') # Bitcoin on Poloniex + + def handle_data(context, data): + # Variables to record for a given asset: price and volume + price = data.current(context.asset, 'price') + volume = data.current(context.asset, 'volume') + record(price=price, volume=volume) + + def analyze(context=None, results=None): + + # Generate DataFrame with Price and Volume only + data = results[['price','volume']] + + # Save results in CSV file + filename = os.path.splitext(os.path.basename(__file__))[0] + data.to_csv(filename + '.csv') + + ''' Bitcoin data is available on Poloniex since 2015-3-1. + Dates vary for other tokens. In the example below, we choose the + full month of July of 2017. + ''' + start = datetime(2017, 1, 1, 0, 0, 0, 0, pytz.utc) + end = datetime(2017, 7, 31, 0, 0, 0, 0, pytz.utc) + results = run_algorithm(initialize=initialize, + handle_data=handle_data, + analyze=analyze, + start=start, + end=end, + exchange_name='poloniex', + capital_base=10000, + base_currency = 'usdt') + +More versatile case for minute data + +.. code-block:: python + + import os + import csv + import pytz + from datetime import datetime + + from catalyst.api import record, symbol, symbols + from catalyst.utils.run_algo import run_algorithm + + + def initialize(context): + # Portfolio assets list + context.asset = symbol('btc_usdt') # Bitcoin on Poloniex + + # Creates a .CSV file with the same name as this script to store results + context.csvfile = open(os.path.splitext( + os.path.basename(__file__))[0]+'.csv', 'w+') + context.csvwriter = csv.writer(context.csvfile) + + def handle_data(context, data): + # Variables to record for a given asset: price and volume + # Other options include 'open', 'high', 'open', 'close' + # Please note that 'price' equals 'close' + date = context.blotter.current_dt # current time in each iteration + price = data.current(context.asset, 'price') + volume = data.current(context.asset, 'volume') + + # Writes one line to CSV on each iteration with the chosen variables + context.csvwriter.writerow([date,price,volume]) + + def analyze(context=None, results=None): + # Close open file properly at the end + context.csvfile.close() + + + # Bitcoin data is available from 2015-3-2. Dates vary for other tokens. + start = datetime(2017, 7, 30, 0, 0, 0, 0, pytz.utc) + end = datetime(2017, 7, 31, 0, 0, 0, 0, pytz.utc) + results = run_algorithm(initialize=initialize, + handle_data=handle_data, + analyze=analyze, + start=start, + end=end, + exchange_name='poloniex', + data_frequency='minute', + base_currency ='usdt', + capital_base=10000 ) \ No newline at end of file