# Example Algorithms¶

This section documents a number of example algorithms to complement the beginner tutorial, and show how other trading algorithms can be implemented using Catalyst.

## Overview¶

• Buy BTC Simple: The simplest algorithm that introduces the `initialize()` and `handle_data()` functions, and is used in the beginner tutorial to show how to run catalyst for the first time.
• Buy and Hodl: A very straightforward buy and hold that makes one single buy at the very beginning. Introduces the notions of `cash`, management of outstanding `orders`, and `order_target_value` to place orders. It also introduces the `analyze()` function to visualize the performance of our strategy using the external library `matplotlib`.
• Dual Moving Average Crossover: A classic momentum strategy used in the second part of the beginner tutorial to introduce the `data.history()` function. It makes a heavy use of `matplotlib` library in the `analyze()` function to chart the performance of the algorithm.
• Mean Reversion Algorithm: Another simple momentum strategy that is used in our two-part video tutorial to show how to get started in backtesting and live trading with Catalyst.
• Simple Universe: This code provides the ‘universe’ of available trading pairs on a given exchange on any given day. You can use this code to dynamically select which currency pairs you want to trade each day of your strategy. This example does not make any trades.
• Portfolio Optimization: Use this code to execute a portfolio optimization model. This strategy will select the portfolio with the maximum Sharpe Ratio. The parameters are set to use 180 days of historical data and rebalance every 30 days. This code was used in writting the following article: Markowitz Portfolio Optimization for Cryptocurrencies.

```"""
This is a very simple example referenced in the beginner's tutorial:
https://enigmampc.github.io/catalyst/beginner-tutorial.html

Run this example, by executing the following from your terminal:
catalyst ingest-exchange -x bitfinex -f daily -i btc_usdt
catalyst run -f buy_btc_simple.py -x bitfinex --start 2016-1-1 \

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
it for exchange Poloniex, you would need to edit the following line:

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 \

To see which assets are available on each exchange, visit:
https://www.enigma.co/catalyst/status
"""
from catalyst import run_algorithm
from catalyst.api import order, record, symbol
import pandas as pd

def initialize(context):
context.asset = symbol('btc_usdt')

def handle_data(context, data):
order(context.asset, 1)
record(btc=data.current(context.asset, 'price'))

if __name__ == '__main__':
run_algorithm(
capital_base=10000,
data_frequency='daily',
initialize=initialize,
handle_data=handle_data,
exchange_name='poloniex',
quote_currency='usdt',
start=pd.to_datetime('2015-03-01', utc=True),
end=pd.to_datetime('2017-10-31', utc=True),
)
```

This simple algorithm does not produce any output nor displays any chart.

First ingest the historical pricing data needed to run this algorithm:

```catalyst ingest-exchange -x bitfinex -f daily -i btc_usd
```

Then, you can run the code below with the following command:

```catalyst run -f buy_and_hodl.py --start 2015-3-1 --end 2017-10-31 --capital-base 100000 -x bitfinex -c btc -o bah.pickle
```

or using the same parameters specified in the run_algorithm() function at the end of the file:

```python buy_and_hodl.py
```

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.

```#!/usr/bin/env python
#
# Copyright 2017 Enigma MPC, Inc.
#
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# Unless required by applicable law or agreed to in writing, software
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
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, )

def initialize(context):
context.ASSET_NAME = 'btc_usdt'
context.TARGET_HODL_RATIO = 0.8
context.RESERVE_RATIO = 1.0 - context.TARGET_HODL_RATIO

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:

# 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,
)

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):

# Plot the portfolio and asset data.
ax1 = plt.subplot(611)
results[['portfolio_value']].plot(ax=ax1)
ax1.set_ylabel('Portfolio\nValue\n(USD)')

ax2 = plt.subplot(612, sharex=ax1)
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]]
[t[0]['amount'] > 0 for t in trans.transactions]
]
ax2.scatter(
marker='^',
s=100,
c='g',
label=''
)

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\nChange')

ax6 = plt.subplot(616, sharex=ax1)
results[['volume']].plot(ax=ax6)
ax6.set_ylabel('Volume')

plt.legend(loc=3)

# Show the plot.
plt.gcf().set_size_inches(18, 8)
plt.show()

if __name__ == '__main__':
run_algorithm(
capital_base=10000,
data_frequency='daily',
initialize=initialize,
handle_data=handle_data,
analyze=analyze,
exchange_name='poloniex',
quote_currency='usdt',
start=pd.to_datetime('2015-03-01', utc=True),
end=pd.to_datetime('2017-10-31', utc=True),
)
```

## Dual Moving Average Crossover¶

This strategy is covered in detail in the last part of this tutorial.

Source Code: examples/dual_moving_average.py

```import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from logbook import Logger

from catalyst import run_algorithm
from catalyst.api import (record, symbol, order_target_percent,)
from catalyst.exchange.utils.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_data = data.history(context.asset,
'price',
bar_count=short_window,
frequency="1T",
)
short_mavg = short_data.mean()
long_data = data.history(context.asset,
'price',
bar_count=long_window,
frequency="1T",
)
long_mavg = long_data.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 = context.blotter.open_orders
if len(orders) > 0:
return

# Exit if we cannot trade
return

# We check what's our position on our portfolio and trade accordingly
pos_amount = context.portfolio.positions[context.asset].amount

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 quote_currency that was passed as a parameter to the simulation
exchange = list(context.exchanges.values())[0]
quote_currency = exchange.quote_currency.upper()

# First chart: Plot portfolio value using quote_currency
ax1 = plt.subplot(411)
perf.loc[:, ['portfolio_value']].plot(ax=ax1)
ax1.legend_.remove()
ax1.set_ylabel('Portfolio Value\n({})'.format(quote_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({quote})'.format(
asset=context.asset.symbol,
quote=quote_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:
sell_df = transaction_df[transaction_df['amount'] < 0]
ax2.scatter(
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(quote_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,
quote_currency='usd',
start=pd.to_datetime('2017-9-22', utc=True),
end=pd.to_datetime('2017-9-23', utc=True),
)
```

## Mean Reversion Algorithm¶

This algorithm is based on a simple momentum strategy. When the cryptoasset goes up quickly, we’re going to buy; when it goes down quickly, we’re going to sell. Hopefully, we’ll ride the waves.

We are choosing to backtest this trading algorithm with the `neo_usd` currency pairon the `Bitfinex` exchange. Thus, first ingest the historical pricing data that we need, with minute resolution:

```catalyst ingest-exchange -x bitfinex -f minute -i neo_usd
```

To run this algorithm, we are opting for the Python interpreter, instead of the command line (CLI). All of the parameters for the simulation are specified in lines 218-245, so in order to run the algorithm we just type:

```python mean_reversion_simple.py
```

Source code: examples/mean_reversion_simple.py

```# For this example, we're going to write a simple momentum script.  When the
# stock goes up quickly, we're going to buy; when it goes down quickly, we're
# going to sell.  Hopefully we'll ride the waves.
import os
import tempfile
import time

import numpy as np
import pandas as pd
import talib
from logbook import Logger

from catalyst import run_algorithm
from catalyst.api import symbol, record, order_target_percent
from catalyst.exchange.utils.stats_utils import extract_transactions
# We give a name to the algorithm which Catalyst will use to persist its state.
# In this example, Catalyst will create the `.catalyst/data/live_algos`
# directory. If we stop and start the algorithm, Catalyst will resume its
# state using the files included in the folder.
from catalyst.utils.paths import ensure_directory

NAMESPACE = 'mean_reversion_simple'
log = Logger(NAMESPACE)

# To run an algorithm in Catalyst, you need two functions: initialize and
# handle_data.

def initialize(context):
# This initialize function sets any data or variables that you'll use in
# your algorithm.  For instance, you'll want to define the trading pair (or
# trading pairs) you want to backtest.  You'll also want to define any
# parameters or values you're going to use.

# In our example, we're looking at Neo in Ether.
context.market = symbol('bnb_eth')
context.base_price = None
context.current_day = None

context.RSI_OVERSOLD = 60
context.RSI_OVERBOUGHT = 70
context.CANDLE_SIZE = '15T'

context.start_time = time.time()

context.set_commission(maker=0.001, taker=0.002)
context.set_slippage(slippage=0.001)

def handle_data(context, data):
# This handle_data function is where the real work is done.  Our data is
# minute-level tick data, and each minute is called a frame.  This function
# runs on each frame of the data.

# We flag the first period of each day.
# would only execute once. This method works with minute and daily
# frequencies.
today = data.current_dt.floor('1D')
if today != context.current_day:
context.current_day = today

# We're computing the volume-weighted-average-price of the security
# defined above, in the context.market variable.  For this example, we're
# using three bars on the 15 min bars.

# The frequency attribute determine the bar size. We use this convention
# for the frequency alias:
# http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
prices = data.history(
context.market,
fields='close',
bar_count=50,
frequency=context.CANDLE_SIZE
)

# Ta-lib calculates various technical indicator based on price and
# volume arrays.

# In this example, we are comp
rsi = talib.RSI(prices.values, timeperiod=14)

# We need a variable for the current price of the security to compare to
# the average. Since we are requesting two fields, data.current()
# returns a DataFrame with
current = data.current(context.market, fields=['close', 'volume'])
price = current['close']

# 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
cash = context.portfolio.cash

# Now that we've collected all current data for this frame, we use
# the record() method to save it. This data will be available as
# a parameter of the analyze() function for further analysis.

record(
volume=current['volume'],
price=price,
price_change=price_change,
rsi=rsi[-1],
cash=cash
)
# We are trying to avoid over-trading by limiting our trades to
# one per day.
return

# TODO: retest with open orders
# Since we are using limit orders, some orders may not execute immediately
# we wait until all orders are executed before considering more trades.
orders = context.blotter.open_orders
if len(orders) > 0:
log.info('exiting because orders are open: {}'.format(orders))
return

# Exit if we cannot trade
return

# Another powerful built-in feature of the Catalyst backtester is the
# portfolio object.  The portfolio object tracks your positions, cash,
# cost basis of specific holdings, and more.  In this line, we calculate
# how long or short our position is at this minute.
pos_amount = context.portfolio.positions[context.market].amount

if rsi[-1] <= context.RSI_OVERSOLD and pos_amount == 0:
log.info(
'{}: buying - price: {}, rsi: {}'.format(
data.current_dt, price, rsi[-1]
)
)
# Set a style for limit orders,
limit_price = price * 1.005
order_target_percent(
context.market, 1, limit_price=limit_price
)

elif rsi[-1] >= context.RSI_OVERBOUGHT and pos_amount > 0:
log.info(
'{}: selling - price: {}, rsi: {}'.format(
data.current_dt, price, rsi[-1]
)
)
limit_price = price * 0.995
order_target_percent(
context.market, 0, limit_price=limit_price
)

def analyze(context=None, perf=None):
end = time.time()
log.info('elapsed time: {}'.format(end - context.start_time))

import matplotlib.pyplot as plt
# The quote currency of the algo exchange
quote_currency = list(context.exchanges.values())[0].quote_currency.upper()

# Plot the portfolio value over time.
ax1 = plt.subplot(611)
perf.loc[:, 'portfolio_value'].plot(ax=ax1)
ax1.set_ylabel('Portfolio\nValue\n({})'.format(quote_currency))

# Plot the price increase or decrease over time.
ax2 = plt.subplot(612, sharex=ax1)
perf.loc[:, 'price'].plot(ax=ax2, label='Price')

ax2.set_ylabel('{asset}\n({quote})'.format(
asset=context.market.symbol, quote=quote_currency
))

transaction_df = extract_transactions(perf)
if not transaction_df.empty:
sell_df = transaction_df[transaction_df['amount'] < 0]
ax2.scatter(
marker='^',
s=100,
c='green',
label=''
)
ax2.scatter(
sell_df.index.to_pydatetime(),
perf.loc[sell_df.index.floor('1 min'), 'price'],
marker='v',
s=100,
c='red',
label=''
)

ax4 = plt.subplot(613, sharex=ax1)
perf.loc[:, 'cash'].plot(
ax=ax4, label='Quote Currency ({})'.format(quote_currency)
)
ax4.set_ylabel('Cash\n({})'.format(quote_currency))

perf['algorithm'] = perf.loc[:, 'algorithm_period_return']

ax5 = plt.subplot(614, sharex=ax1)
perf.loc[:, ['algorithm', 'price_change']].plot(ax=ax5)
ax5.set_ylabel('Percent\nChange')

ax6 = plt.subplot(615, sharex=ax1)
perf.loc[:, 'rsi'].plot(ax=ax6, label='RSI')
ax6.set_ylabel('RSI')
ax6.axhline(context.RSI_OVERBOUGHT, color='darkgoldenrod')
ax6.axhline(context.RSI_OVERSOLD, color='darkgoldenrod')

if not transaction_df.empty:
ax6.scatter(
marker='^',
s=100,
c='green',
label=''
)
ax6.scatter(
sell_df.index.to_pydatetime(),
perf.loc[sell_df.index.floor('1 min'), 'rsi'],
marker='v',
s=100,
c='red',
label=''
)
plt.legend(loc=3)
start, end = ax6.get_ylim()
ax6.yaxis.set_ticks(np.arange(0, end, end / 5))

# Show the plot.
plt.gcf().set_size_inches(18, 8)
plt.show()
pass

if __name__ == '__main__':
# The execution mode: backtest or live
live = True

if live:
run_algorithm(
capital_base=0.1,
initialize=initialize,
handle_data=handle_data,
analyze=analyze,
exchange_name='binance',
live=True,
algo_namespace=NAMESPACE,
quote_currency='eth',
live_graph=False,
simulate_orders=False,
stats_output=None,
# auth_aliases=dict(poloniex='auth2')
)

else:
folder = os.path.join(
tempfile.gettempdir(), 'catalyst', NAMESPACE
)
ensure_directory(folder)

timestr = time.strftime('%Y%m%d-%H%M%S')
out = os.path.join(folder, '{}.p'.format(timestr))
# catalyst run -f catalyst/examples/mean_reversion_simple.py \
#    -x bitfinex -s 2017-10-1 -e 2017-11-10 -c usdt -n mean-reversion \
#   --data-frequency minute --capital-base 10000
run_algorithm(
capital_base=0.035,
data_frequency='minute',
initialize=initialize,
handle_data=handle_data,
analyze=analyze,
exchange_name='bitfinex',
algo_namespace=NAMESPACE,
quote_currency='btc',
start=pd.to_datetime('2017-10-01', utc=True),
end=pd.to_datetime('2017-11-10', utc=True),
output=out
)
log.info('saved perf stats: {}'.format(out))
```

Notice the difference in performance between the charts above and those seen on this video tutorial at minute 8:10. The buy and sell orders are triggered at the same exact times, but the differences result from a more realistic slippage model implemented after the video was recorded, which executes the orders at slighlty different prices, but resulting in significant changes in performance of our strategy.

## Simple Universe¶

This example aims to provide an easy way for users to learn how to collect data from any given exchange and select a subset of the available currency pairs for trading. You simply need to specify the exchange and the market (quote_currency) that you want to focus on. You will then see how to create a universe of assets, and filter it based on the market you desire.

The example prints out the closing price of all the pairs for a given market in a given exchange every 30 minutes. The example also contains the OHLCV data with minute-resolution for the past seven days which could be used to create indicators. Use this code as the backbone to create your own trading strategy.

The lookback_date variable is used to ensure data for a coin existed on the lookback period specified.

To run, execute the following two commands in a terminal (inside catalyst environment). The first one retrieves all the pricing data needed for this script to run (only needs to be run once), and the second one executes this script with the parameters specified in the run_algorithm() call at the end of the file:

```catalyst ingest-exchange -x bitfinex -f minute
```

Source code: examples/simple_universe.py

```"""
Requires Catalyst version 0.3.0 or above
Tested on Catalyst version 0.3.3

This example aims to provide an easy way for users to learn how to
collect data from any given exchange and select a subset of the available
currency pairs for trading. You simply need to specify the exchange and
the market (quote_currency) that you want to focus on. You will then see
how to create a universe of assets, and filter it based the market you
desire.

The example prints out the closing price of all the pairs for a given
market in a given exchange every 30 minutes. The example also contains
the OHLCV data with minute-resolution for the past seven days which
could be used to create indicators. Use this code as the backbone to

The lookback_date variable is used to ensure data for a coin existed on
the lookback period specified.

To run, execute the following two commands in a terminal (inside catalyst
environment). The first one retrieves all the pricing data needed for this
script to run (only needs to be run once), and the second one executes this
script with the parameters specified in the run_algorithm() call at the end
of the file:

catalyst ingest-exchange -x bitfinex -f minute

python simple_universe.py

"""
from datetime import timedelta

import numpy as np
import pandas as pd

from catalyst import run_algorithm
from catalyst.api import (symbols, )
from catalyst.exchange.utils.exchange_utils import get_exchange_symbols

def initialize(context):
context.i = -1  # minute counter
context.exchange = list(context.exchanges.values())[0].name.lower()
context.quote_currency = list(
context.exchanges.values())[0].quote_currency.lower()

def handle_data(context, data):
context.i += 1
lookback_days = 7  # 7 days

# current date & time in each iteration formatted into a string
now = data.current_dt
date, time = now.strftime('%Y-%m-%d %H:%M:%S').split(' ')
lookback_date = now - timedelta(days=lookback_days)
# keep only the date as a string, discard the time
lookback_date = lookback_date.strftime('%Y-%m-%d %H:%M:%S').split(' ')[0]

one_day_in_minutes = 1440  # 60 * 24 assumes data_frequency='minute'
# update universe everyday at midnight
if not context.i % one_day_in_minutes:
context.universe = universe(context, lookback_date, date)

# get data every 30 minutes
minutes = 30

# get lookback_days of history data: that is 'lookback' number of bins
lookback = int(one_day_in_minutes / minutes * lookback_days)
if not context.i % minutes and context.universe:
# we iterate for every pair in the current universe
for coin in context.coins:
pair = str(coin.symbol)

# Get 30 minute interval OHLCV data. This is the standard data
# required for candlestick or indicators/signals. Return Pandas
# DataFrames. 30T means 30-minute re-sampling of one minute data.
opened = fill(data.history(coin,
'open',
bar_count=lookback,
frequency='30T')).values
high = fill(data.history(coin,
'high',
bar_count=lookback,
frequency='30T')).values
low = fill(data.history(coin,
'low',
bar_count=lookback,
frequency='30T')).values
close = fill(data.history(coin,
'price',
bar_count=lookback,
frequency='30T')).values
volume = fill(data.history(coin,
'volume',
bar_count=lookback,
frequency='30T')).values

# close[-1] is the last value in the set, which is the equivalent
# to current price (as in the most recent value)
# displays the minute price for each pair every 30 minutes
print('{now}: {pair} -\tO:{o},\tH:{h},\tL:{c},\tC{c},'
'\tV:{v}'.format(
now=now,
pair=pair,
o=opened[-1],
h=high[-1],
l=low[-1],
c=close[-1],
v=volume[-1],
))

# -------------------------------------------------------------
# --------------- Insert Your Strategy Here -------------------
# -------------------------------------------------------------

def analyze(context=None, results=None):
pass

# Get the universe for a given exchange and a given quote_currency market
# Example: Poloniex BTC Market
def universe(context, lookback_date, current_date):
# get all the pairs for the given exchange
json_symbols = get_exchange_symbols(context.exchange)
# convert into a DataFrame for easier processing
df = pd.DataFrame.from_dict(json_symbols).transpose().astype(str)
df['quote_currency'] = df.apply(lambda row: row.symbol.split('_')[1],
axis=1)
df['base_currency'] = df.apply(lambda row: row.symbol.split('_')[0],
axis=1)

# Filter all the pairs to get only the ones for a given quote_currency
df = df[df['quote_currency'] == context.quote_currency]

# Filter all pairs to ensure that pair existed in the current date range
df = df[df.start_date < lookback_date]
df = df[df.end_daily >= current_date]
context.coins = symbols(*df.symbol)  # convert all the pairs to symbols

return df.symbol.tolist()

# Replace all NA, NAN or infinite values with its nearest value
def fill(series):
if isinstance(series, pd.Series):
return series.replace([np.inf, -np.inf], np.nan).ffill().bfill()
elif isinstance(series, np.ndarray):
return pd.Series(series).replace(
[np.inf, -np.inf], np.nan
).ffill().bfill().values
else:
return series

if __name__ == '__main__':
start_date = pd.to_datetime('2017-11-10', utc=True)
end_date = pd.to_datetime('2017-11-13', utc=True)

performance = run_algorithm(start=start_date, end=end_date,
capital_base=100.0,  # amount of quote_currency
initialize=initialize,
handle_data=handle_data,
analyze=analyze,
exchange_name='poloniex',
data_frequency='minute',
quote_currency='btc',
live=False,
live_graph=False,
algo_namespace='simple_universe')
```

## Portfolio Optimization¶

Use this code to execute a portfolio optimization model. This strategy will select the portfolio with the maximum Sharpe Ratio. The parameters are set to use 180 days of historical data and rebalance every 30 days. This code was used in writting the following article: Markowitz Portfolio Optimization for Cryptocurrencies.

Source code: examples/portfolio_optimization.py

```'''Use this code to execute a portfolio optimization model. This code
will select the portfolio with the maximum Sharpe Ratio. The parameters
are set to use 180 days of historical data and rebalance every 30 days.

This is the code used in the following article:
https://blog.enigma.co/markowitz-portfolio-optimization-for-cryptocurrencies-in-catalyst-b23c38652556

You can run this code using the Python interpreter:

\$ python portfolio_optimization.py
'''

from __future__ import division
import os
import pytz
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime

from catalyst.api import record, symbols, order_target_percent
from catalyst.utils.run_algo import run_algorithm

np.set_printoptions(threshold=np.nan, suppress=True)

def initialize(context):
# Portfolio assets list
context.assets = symbols('btc_usdt', 'eth_usdt', 'ltc_usdt', 'dash_usdt',
'xmr_usdt')
context.nassets = len(context.assets)
# Set the time window that will be used to compute expected return
# and asset correlations
context.window = 180
# Set the number of days between each portfolio rebalancing
context.rebalance_period = 30
context.i = 0

def handle_data(context, data):
# Only rebalance at the beginning of the algorithm execution and
# every multiple of the rebalance period
if context.i == 0 or context.i % context.rebalance_period == 0:
n = context.window
prices = data.history(context.assets, fields='price',
bar_count=n + 1, frequency='1d')
pr = np.asmatrix(prices)
t_prices = prices.iloc[1:n + 1]
t_val = t_prices.values
tminus_prices = prices.iloc[0:n]
tminus_val = tminus_prices.values
# Compute daily returns (r)
r = np.asmatrix(t_val / tminus_val - 1)
# Compute the expected returns of each asset with the average
# daily return for the selected time window
m = np.asmatrix(np.mean(r, axis=0))
# ###
stds = np.std(r, axis=0)
# Compute excess returns matrix (xr)
xr = r - m
# Matrix algebra to get variance-covariance matrix
cov_m = np.dot(np.transpose(xr), xr) / n
# Compute asset correlation matrix (informative only)
corr_m = cov_m / np.dot(np.transpose(stds), stds)

# Define portfolio optimization parameters
n_portfolios = 50000
results_array = np.zeros((3 + context.nassets, n_portfolios))
for p in range(n_portfolios):
weights = np.random.random(context.nassets)
weights /= np.sum(weights)
w = np.asmatrix(weights)
p_r = np.sum(np.dot(w, np.transpose(m))) * 365
p_std = np.sqrt(np.dot(np.dot(w, cov_m),
np.transpose(w))) * np.sqrt(365)

# store results in results array
results_array[0, p] = p_r
results_array[1, p] = p_std
# store Sharpe Ratio (return / volatility) - risk free rate element
# excluded for simplicity
results_array[2, p] = results_array[0, p] / results_array[1, p]

for i, w in enumerate(weights):
results_array[3 + i, p] = w

columns = ['r', 'stdev', 'sharpe'] + context.assets

# convert results array to Pandas DataFrame
results_frame = pd.DataFrame(np.transpose(results_array),
columns=columns)
# locate position of portfolio with highest Sharpe Ratio
max_sharpe_port = results_frame.iloc[results_frame['sharpe'].idxmax()]
# locate positon of portfolio with minimum standard deviation
# min_vol_port = results_frame.iloc[results_frame['stdev'].idxmin()]

# order optimal weights for each asset
for asset in context.assets:
order_target_percent(asset, max_sharpe_port[asset])

# create scatter plot coloured by Sharpe Ratio
plt.scatter(results_frame.stdev,
results_frame.r,
c=results_frame.sharpe,
cmap='RdYlGn')
plt.xlabel('Volatility')
plt.ylabel('Returns')
plt.colorbar()

# plot blue circle to highlight position of portfolio
# with highest Sharpe Ratio
plt.scatter(max_sharpe_port[1],
max_sharpe_port[0],
marker='o',
color='b',
s=200)

plt.show()
print(max_sharpe_port)
record(pr=pr,
r=r,
m=m,
stds=stds,
max_sharpe_port=max_sharpe_port,
corr_m=corr_m)
context.i += 1

def analyze(context=None, results=None):
# Form DataFrame with selected data
data = results[['pr', 'r', 'm', 'stds', 'max_sharpe_port', 'corr_m',
'portfolio_value']]

# Save results in CSV file
filename = os.path.splitext(os.path.basename(__file__))[0]
data.to_csv(filename + '.csv')

if __name__ == '__main__':
# Bitcoin data is available from 2015-3-2. Dates vary for other tokens.
start = datetime(2017, 1, 1, 0, 0, 0, 0, pytz.utc)
end = datetime(2017, 8, 16, 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=100000,
quote_currency='usdt')
```