mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-22 12:40:30 +08:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c571c1c2ae | ||
|
|
f279101393 | ||
|
|
96a27d083c | ||
|
|
f995f451a7 | ||
|
|
a3838fc00f | ||
|
|
4db8131397 | ||
|
|
207bce6216 | ||
|
|
8fb8b80a12 | ||
|
|
b762689225 | ||
|
|
7bbb6e0b42 | ||
|
|
b587804e3e | ||
|
|
5660247da2 | ||
|
|
fc2c44a6b7 | ||
|
|
4eb8a6eb0f | ||
|
|
c8eaa11f80 | ||
|
|
55a9d76b9b | ||
|
|
7abd992d17 | ||
|
|
daeccaed36 | ||
|
|
25358a4077 | ||
|
|
7cf4f84e89 | ||
|
|
b63199e4e1 | ||
|
|
4af08be7e8 | ||
|
|
606148e19c | ||
|
|
d38e560265 | ||
|
|
ffd1bc07cc | ||
|
|
dfcfe5a370 |
+35
-13
@@ -396,11 +396,15 @@ cdef class Future(Asset):
|
|||||||
|
|
||||||
cdef class TradingPair(Asset):
|
cdef class TradingPair(Asset):
|
||||||
cdef readonly float leverage
|
cdef readonly float leverage
|
||||||
cdef readonly object market_currency
|
cdef readonly object quote_currency
|
||||||
cdef readonly object base_currency
|
cdef readonly object base_currency
|
||||||
cdef readonly object end_daily
|
cdef readonly object end_daily
|
||||||
cdef readonly object end_minute
|
cdef readonly object end_minute
|
||||||
cdef readonly object exchange_symbol
|
cdef readonly object exchange_symbol
|
||||||
|
cdef readonly float maker
|
||||||
|
cdef readonly float taker
|
||||||
|
cdef readonly int trading_state
|
||||||
|
cdef readonly object data_source
|
||||||
|
|
||||||
_kwargnames = frozenset({
|
_kwargnames = frozenset({
|
||||||
'sid',
|
'sid',
|
||||||
@@ -413,12 +417,16 @@ cdef class TradingPair(Asset):
|
|||||||
'exchange',
|
'exchange',
|
||||||
'exchange_full',
|
'exchange_full',
|
||||||
'leverage',
|
'leverage',
|
||||||
'market_currency',
|
'quote_currency',
|
||||||
'base_currency',
|
'base_currency',
|
||||||
'end_daily',
|
'end_daily',
|
||||||
'end_minute',
|
'end_minute',
|
||||||
'exchange_symbol',
|
'exchange_symbol',
|
||||||
'min_trade_size'
|
'min_trade_size',
|
||||||
|
'maker',
|
||||||
|
'taker',
|
||||||
|
'trading_state',
|
||||||
|
'data_source'
|
||||||
})
|
})
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
object symbol,
|
object symbol,
|
||||||
@@ -434,10 +442,14 @@ cdef class TradingPair(Asset):
|
|||||||
object first_traded=None,
|
object first_traded=None,
|
||||||
object auto_close_date=None,
|
object auto_close_date=None,
|
||||||
object exchange_full=None,
|
object exchange_full=None,
|
||||||
object min_trade_size=None):
|
float min_trade_size=0.0001,
|
||||||
|
float maker=0.0015,
|
||||||
|
float taker=0.0025,
|
||||||
|
int trading_state=0,
|
||||||
|
object data_source='catalyst'):
|
||||||
"""
|
"""
|
||||||
Replicates the Asset constructor with some built-in conventions
|
Replicates the Asset constructor with some built-in conventions
|
||||||
and a new 'leverage' attribute.
|
and adds properties for leverage and fees.
|
||||||
|
|
||||||
Symbol
|
Symbol
|
||||||
------
|
------
|
||||||
@@ -469,8 +481,6 @@ cdef class TradingPair(Asset):
|
|||||||
highest volume and market cap generally benefit from high leverage.
|
highest volume and market cap generally benefit from high leverage.
|
||||||
New currencies from ICO generally cannot be leveraged.
|
New currencies from ICO generally cannot be leveraged.
|
||||||
|
|
||||||
The leverage value is either None or and integer.
|
|
||||||
|
|
||||||
Leverage allows you to open a larger position with a smaller amount
|
Leverage allows you to open a larger position with a smaller amount
|
||||||
of funds. For example, if you open a $5,000 position in BTC/USD
|
of funds. For example, if you open a $5,000 position in BTC/USD
|
||||||
with 5:1 leverage, only one-fifth of this amount, or $1000, will be
|
with 5:1 leverage, only one-fifth of this amount, or $1000, will be
|
||||||
@@ -480,6 +490,11 @@ cdef class TradingPair(Asset):
|
|||||||
the position. If you open with 1:1 leverage, $5,000 of your balance
|
the position. If you open with 1:1 leverage, $5,000 of your balance
|
||||||
will be tied to the position.
|
will be tied to the position.
|
||||||
|
|
||||||
|
Fees
|
||||||
|
----
|
||||||
|
Exchanges generally charge a taker (taking from the order book) or
|
||||||
|
maker (adding to the order book) fee.
|
||||||
|
|
||||||
:param symbol:
|
:param symbol:
|
||||||
:param exchange:
|
:param exchange:
|
||||||
:param start_date:
|
:param start_date:
|
||||||
@@ -494,11 +509,14 @@ cdef class TradingPair(Asset):
|
|||||||
:param auto_close_date:
|
:param auto_close_date:
|
||||||
:param exchange_full:
|
:param exchange_full:
|
||||||
:param min_trade_size:
|
:param min_trade_size:
|
||||||
|
:param maker:
|
||||||
|
:param taker:
|
||||||
|
:param data_source
|
||||||
"""
|
"""
|
||||||
|
|
||||||
symbol = symbol.lower()
|
symbol = symbol.lower()
|
||||||
try:
|
try:
|
||||||
self.market_currency, self.base_currency = symbol.split('_')
|
self.base_currency, self.quote_currency = symbol.split('_')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise InvalidSymbolError(symbol=symbol, error=e)
|
raise InvalidSymbolError(symbol=symbol, error=e)
|
||||||
|
|
||||||
@@ -512,7 +530,7 @@ cdef class TradingPair(Asset):
|
|||||||
asset_name = ' / '.join(symbol.split('_')).upper()
|
asset_name = ' / '.join(symbol.split('_')).upper()
|
||||||
|
|
||||||
if start_date is None:
|
if start_date is None:
|
||||||
start_date = pd.Timestamp.utcnow()
|
start_date = pd.to_datetime('2009-1-1', utc=True)
|
||||||
|
|
||||||
if end_date is None:
|
if end_date is None:
|
||||||
end_date = pd.Timestamp.utcnow() + timedelta(days=365)
|
end_date = pd.Timestamp.utcnow() + timedelta(days=365)
|
||||||
@@ -527,19 +545,23 @@ cdef class TradingPair(Asset):
|
|||||||
first_traded=first_traded,
|
first_traded=first_traded,
|
||||||
auto_close_date=auto_close_date,
|
auto_close_date=auto_close_date,
|
||||||
exchange_full=exchange_full,
|
exchange_full=exchange_full,
|
||||||
min_trade_size=min_trade_size
|
min_trade_size=min_trade_size,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.maker = maker
|
||||||
|
self.taker = taker
|
||||||
self.leverage = leverage
|
self.leverage = leverage
|
||||||
self.end_daily = end_daily
|
self.end_daily = end_daily
|
||||||
self.end_minute = end_minute
|
self.end_minute = end_minute
|
||||||
self.exchange_symbol = exchange_symbol
|
self.exchange_symbol = exchange_symbol
|
||||||
|
self.trading_state = trading_state
|
||||||
|
self.data_source = data_source
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Trading Pair {symbol}({sid}) Exchange: {exchange}, ' \
|
return 'Trading Pair {symbol}({sid}) Exchange: {exchange}, ' \
|
||||||
'Introduced On: {start_date}, ' \
|
'Introduced On: {start_date}, ' \
|
||||||
'Market Currency: {market_currency}, ' \
|
|
||||||
'Base Currency: {base_currency}, ' \
|
'Base Currency: {base_currency}, ' \
|
||||||
|
'Quote Currency: {quote_currency}, ' \
|
||||||
'Exchange Leverage: {leverage}, ' \
|
'Exchange Leverage: {leverage}, ' \
|
||||||
'Minimum Trade Size: {min_trade_size} ' \
|
'Minimum Trade Size: {min_trade_size} ' \
|
||||||
'Last daily ingestion: {end_daily} ' \
|
'Last daily ingestion: {end_daily} ' \
|
||||||
@@ -548,7 +570,7 @@ cdef class TradingPair(Asset):
|
|||||||
sid=self.sid,
|
sid=self.sid,
|
||||||
exchange=self.exchange,
|
exchange=self.exchange,
|
||||||
start_date=self.start_date,
|
start_date=self.start_date,
|
||||||
market_currency=self.market_currency,
|
quote_currency=self.quote_currency,
|
||||||
base_currency=self.base_currency,
|
base_currency=self.base_currency,
|
||||||
leverage=self.leverage,
|
leverage=self.leverage,
|
||||||
min_trade_size=self.min_trade_size,
|
min_trade_size=self.min_trade_size,
|
||||||
@@ -578,7 +600,7 @@ cdef class TradingPair(Asset):
|
|||||||
-------
|
-------
|
||||||
boolean: whether the asset's exchange is open at the given minute.
|
boolean: whether the asset's exchange is open at the given minute.
|
||||||
"""
|
"""
|
||||||
#TODO: consider implementing to spot holds
|
#TODO: make more dymanic to catch holds
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cpdef __reduce__(self):
|
cpdef __reduce__(self):
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import logbook
|
|||||||
For example, if you want to see the DEBUG messages, run:
|
For example, if you want to see the DEBUG messages, run:
|
||||||
$ export CATALYST_LOG_LEVEL=10
|
$ export CATALYST_LOG_LEVEL=10
|
||||||
'''
|
'''
|
||||||
LOG_LEVEL = int(os.environ.get('CATALYST_LOG_LEVEL', logbook.INFO))
|
# LOG_LEVEL = int(os.environ.get('CATALYST_LOG_LEVEL', logbook.INFO))
|
||||||
|
LOG_LEVEL = logbook.DEBUG
|
||||||
|
|
||||||
SYMBOLS_URL = 'https://s3.amazonaws.com/enigmaco/catalyst-exchanges/' \
|
SYMBOLS_URL = 'https://s3.amazonaws.com/enigmaco/catalyst-exchanges/' \
|
||||||
'{exchange}/symbols.json'
|
'{exchange}/symbols.json'
|
||||||
|
|||||||
@@ -142,8 +142,10 @@ def load_crypto_market_data(trading_day=None, trading_days=None,
|
|||||||
if exchange is None:
|
if exchange is None:
|
||||||
# This is exceptional, since placing the import at the module scope
|
# This is exceptional, since placing the import at the module scope
|
||||||
# breaks things and it's only needed here
|
# breaks things and it's only needed here
|
||||||
from catalyst.exchange.poloniex.poloniex import Poloniex
|
from catalyst.exchange.factory import get_exchange
|
||||||
exchange = Poloniex('', '', '')
|
exchange = get_exchange(
|
||||||
|
exchange_name='poloniex', base_currency='usdt'
|
||||||
|
)
|
||||||
|
|
||||||
benchmark_asset = exchange.get_asset(bm_symbol)
|
benchmark_asset = exchange.get_asset(bm_symbol)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
An overview of most of the trading strategies in this folder can be found in the
|
||||||
|
`Examples Algorithms <https://enigmampc.github.io/catalyst/example-algos.html>`_
|
||||||
|
section of our documentation website.
|
||||||
@@ -83,15 +83,15 @@ def place_orders(context, amount, buying_price, selling_price, action):
|
|||||||
else:
|
else:
|
||||||
raise ValueError('invalid order action')
|
raise ValueError('invalid order action')
|
||||||
|
|
||||||
base_currency = enter_exchange.base_currency
|
quote_currency = enter_exchange.quote_currency
|
||||||
base_currency_amount = enter_exchange.portfolio.cash
|
quote_currency_amount = enter_exchange.portfolio.cash
|
||||||
|
|
||||||
exit_balances = exit_exchange.get_balances()
|
exit_balances = exit_exchange.get_balances()
|
||||||
exit_currency = context.trading_pairs[
|
exit_currency = context.trading_pairs[
|
||||||
context.selling_exchange].market_currency
|
context.selling_exchange].quote_currency
|
||||||
|
|
||||||
if exit_currency in exit_balances:
|
if exit_currency in exit_balances:
|
||||||
market_currency_amount = exit_balances[exit_currency]
|
quote_currency_amount = exit_balances[exit_currency]
|
||||||
else:
|
else:
|
||||||
log.warn(
|
log.warn(
|
||||||
'the selling exchange {exchange_name} does not hold '
|
'the selling exchange {exchange_name} does not hold '
|
||||||
@@ -102,25 +102,25 @@ def place_orders(context, amount, buying_price, selling_price, action):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if base_currency_amount < (amount * entry_price):
|
if quote_currency_amount < (amount * entry_price):
|
||||||
adj_amount = base_currency_amount / entry_price
|
adj_amount = quote_currency_amount / entry_price
|
||||||
log.warn(
|
log.warn(
|
||||||
'not enough {base_currency} ({base_currency_amount}) to buy '
|
'not enough {quote_currency} ({quote_currency_amount}) to buy '
|
||||||
'{amount}, adjusting the amount to {adj_amount}'.format(
|
'{amount}, adjusting the amount to {adj_amount}'.format(
|
||||||
base_currency=base_currency,
|
quote_currency=quote_currency,
|
||||||
base_currency_amount=base_currency_amount,
|
quote_currency_amount=quote_currency_amount,
|
||||||
amount=amount,
|
amount=amount,
|
||||||
adj_amount=adj_amount
|
adj_amount=adj_amount
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
amount = adj_amount
|
amount = adj_amount
|
||||||
|
|
||||||
elif market_currency_amount < amount:
|
elif quote_currency_amount < amount:
|
||||||
log.warn(
|
log.warn(
|
||||||
'not enough {currency} ({currency_amount}) to sell '
|
'not enough {currency} ({currency_amount}) to sell '
|
||||||
'{amount}, aborting'.format(
|
'{amount}, aborting'.format(
|
||||||
currency=exit_currency,
|
currency=exit_currency,
|
||||||
currency_amount=market_currency_amount,
|
currency_amount=quote_currency_amount,
|
||||||
amount=amount
|
amount=amount
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -270,6 +270,6 @@ run_algorithm(
|
|||||||
exchange_name='poloniex,bitfinex',
|
exchange_name='poloniex,bitfinex',
|
||||||
live=True,
|
live=True,
|
||||||
algo_namespace=algo_namespace,
|
algo_namespace=algo_namespace,
|
||||||
base_currency='btc',
|
quote_currency='btc',
|
||||||
live_graph=False
|
live_graph=False
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,15 +15,11 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
from catalyst import run_algorithm
|
from catalyst import run_algorithm
|
||||||
from catalyst.api import (
|
from catalyst.api import (order_target_value, symbol, record,
|
||||||
order_target_value,
|
cancel_order, get_open_orders, )
|
||||||
symbol,
|
|
||||||
record,
|
|
||||||
cancel_order,
|
|
||||||
get_open_orders,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def initialize(context):
|
def initialize(context):
|
||||||
@@ -78,15 +74,14 @@ def handle_data(context, data):
|
|||||||
|
|
||||||
|
|
||||||
def analyze(context=None, results=None):
|
def analyze(context=None, results=None):
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
# Plot the portfolio and asset data.
|
# Plot the portfolio and asset data.
|
||||||
ax1 = plt.subplot(611)
|
ax1 = plt.subplot(611)
|
||||||
results[['portfolio_value']].plot(ax=ax1)
|
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 = 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)
|
results[['price']].plot(ax=ax2)
|
||||||
|
|
||||||
trans = results.ix[[t != [] for t in results.transactions]]
|
trans = results.ix[[t != [] for t in results.transactions]]
|
||||||
@@ -126,11 +121,11 @@ def analyze(context=None, results=None):
|
|||||||
'algorithm',
|
'algorithm',
|
||||||
'benchmark',
|
'benchmark',
|
||||||
]].plot(ax=ax5)
|
]].plot(ax=ax5)
|
||||||
ax5.set_ylabel('Percent Change')
|
ax5.set_ylabel('Percent\nChange')
|
||||||
|
|
||||||
ax6 = plt.subplot(616, sharex=ax1)
|
ax6 = plt.subplot(616, sharex=ax1)
|
||||||
results[['volume']].plot(ax=ax6)
|
results[['volume']].plot(ax=ax6)
|
||||||
ax6.set_ylabel('Volume (mCoins/5min)')
|
ax6.set_ylabel('Volume')
|
||||||
|
|
||||||
plt.legend(loc=3)
|
plt.legend(loc=3)
|
||||||
|
|
||||||
@@ -142,13 +137,13 @@ def analyze(context=None, results=None):
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
run_algorithm(
|
run_algorithm(
|
||||||
capital_base=10000,
|
capital_base=10000,
|
||||||
data_frequency='minute',
|
data_frequency='daily',
|
||||||
initialize=initialize,
|
initialize=initialize,
|
||||||
handle_data=handle_data,
|
handle_data=handle_data,
|
||||||
analyze=analyze,
|
analyze=analyze,
|
||||||
exchange_name='bitfinex',
|
exchange_name='bitfinex',
|
||||||
algo_namespace='buy_and_hodl',
|
algo_namespace='buy_and_hodl',
|
||||||
base_currency='usd',
|
base_currency='usd',
|
||||||
start=pd.to_datetime('2017-11-01', utc=True),
|
start=pd.to_datetime('2015-03-01', utc=True),
|
||||||
end=pd.to_datetime('2017-11-10', utc=True),
|
end=pd.to_datetime('2017-10-31', utc=True),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
https://enigmampc.github.io/catalyst/beginner-tutorial.html
|
https://enigmampc.github.io/catalyst/beginner-tutorial.html
|
||||||
|
|
||||||
Run this example, by executing the following from your terminal:
|
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 --end 2017-9-30 -o buy_btc_simple_out.pickle
|
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
|
If you want to run this code using another exchange, make sure that
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
context.asset = symbol('btc_usdt') # note 'usdt' instead of 'usd'
|
context.asset = symbol('btc_usdt') # note 'usdt' instead of 'usd'
|
||||||
|
|
||||||
and specify exchange poloniex as follows:
|
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
|
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:
|
To see which assets are available on each exchange, visit:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import os
|
|||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import talib
|
import talib
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
@@ -31,13 +32,13 @@ def initialize(context):
|
|||||||
# trading pairs) you want to backtest. You'll also want to define any
|
# trading pairs) you want to backtest. You'll also want to define any
|
||||||
# parameters or values you're going to use.
|
# parameters or values you're going to use.
|
||||||
|
|
||||||
# In our example, we're looking at Ether in USD Tether.
|
# In our example, we're looking at Neo in Ether.
|
||||||
context.neo_eth = symbol('neo_eth')
|
context.neo_eth = symbol('neo_eth')
|
||||||
context.base_price = None
|
context.base_price = None
|
||||||
context.current_day = None
|
context.current_day = None
|
||||||
|
|
||||||
context.RSI_OVERSOLD = 50
|
context.RSI_OVERSOLD = 55
|
||||||
context.RSI_OVERBOUGHT = 80
|
context.RSI_OVERBOUGHT = 82
|
||||||
context.CANDLE_SIZE = '5T'
|
context.CANDLE_SIZE = '5T'
|
||||||
|
|
||||||
context.start_time = time.time()
|
context.start_time = time.time()
|
||||||
@@ -160,13 +161,13 @@ def analyze(context=None, perf=None):
|
|||||||
# Plot the portfolio value over time.
|
# Plot the portfolio value over time.
|
||||||
ax1 = plt.subplot(611)
|
ax1 = plt.subplot(611)
|
||||||
perf.loc[:, 'portfolio_value'].plot(ax=ax1)
|
perf.loc[:, 'portfolio_value'].plot(ax=ax1)
|
||||||
ax1.set_ylabel('Portfolio Value ({})'.format(base_currency))
|
ax1.set_ylabel('Portfolio\nValue\n({})'.format(base_currency))
|
||||||
|
|
||||||
# Plot the price increase or decrease over time.
|
# Plot the price increase or decrease over time.
|
||||||
ax2 = plt.subplot(612, sharex=ax1)
|
ax2 = plt.subplot(612, sharex=ax1)
|
||||||
perf.loc[:, 'price'].plot(ax=ax2, label='Price')
|
perf.loc[:, 'price'].plot(ax=ax2, label='Price')
|
||||||
|
|
||||||
ax2.set_ylabel('{asset} ({base})'.format(
|
ax2.set_ylabel('{asset}\n({base})'.format(
|
||||||
asset=context.neo_eth.symbol, base=base_currency
|
asset=context.neo_eth.symbol, base=base_currency
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -195,18 +196,19 @@ def analyze(context=None, perf=None):
|
|||||||
perf.loc[:, 'cash'].plot(
|
perf.loc[:, 'cash'].plot(
|
||||||
ax=ax4, label='Base Currency ({})'.format(base_currency)
|
ax=ax4, label='Base Currency ({})'.format(base_currency)
|
||||||
)
|
)
|
||||||
ax4.set_ylabel('Cash ({})'.format(base_currency))
|
ax4.set_ylabel('Cash\n({})'.format(base_currency))
|
||||||
|
|
||||||
perf['algorithm'] = perf.loc[:, 'algorithm_period_return']
|
perf['algorithm'] = perf.loc[:, 'algorithm_period_return']
|
||||||
|
|
||||||
ax5 = plt.subplot(614, sharex=ax1)
|
ax5 = plt.subplot(614, sharex=ax1)
|
||||||
perf.loc[:, ['algorithm', 'price_change']].plot(ax=ax5)
|
perf.loc[:, ['algorithm', 'price_change']].plot(ax=ax5)
|
||||||
ax5.set_ylabel('Percent Change')
|
ax5.set_ylabel('Percent\nChange')
|
||||||
|
|
||||||
ax6 = plt.subplot(615, sharex=ax1)
|
ax6 = plt.subplot(615, sharex=ax1)
|
||||||
perf.loc[:, 'rsi'].plot(ax=ax6, label='RSI')
|
perf.loc[:, 'rsi'].plot(ax=ax6, label='RSI')
|
||||||
ax6.axhline(70, color='darkgoldenrod')
|
ax6.set_ylabel('RSI')
|
||||||
ax6.axhline(30, color='darkgoldenrod')
|
ax6.axhline(context.RSI_OVERBOUGHT, color='darkgoldenrod')
|
||||||
|
ax6.axhline(context.RSI_OVERSOLD, color='darkgoldenrod')
|
||||||
|
|
||||||
if not transaction_df.empty:
|
if not transaction_df.empty:
|
||||||
ax6.scatter(
|
ax6.scatter(
|
||||||
@@ -226,6 +228,8 @@ def analyze(context=None, perf=None):
|
|||||||
label=''
|
label=''
|
||||||
)
|
)
|
||||||
plt.legend(loc=3)
|
plt.legend(loc=3)
|
||||||
|
start, end = ax6.get_ylim()
|
||||||
|
ax6.yaxis.set_ticks(np.arange(0, end, end/5))
|
||||||
|
|
||||||
# Show the plot.
|
# Show the plot.
|
||||||
plt.gcf().set_size_inches(18, 8)
|
plt.gcf().set_size_inches(18, 8)
|
||||||
@@ -235,7 +239,7 @@ def analyze(context=None, perf=None):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# The execution mode: backtest or live
|
# The execution mode: backtest or live
|
||||||
MODE = 'backtest'
|
MODE = 'live'
|
||||||
|
|
||||||
if MODE == 'backtest':
|
if MODE == 'backtest':
|
||||||
folder = os.path.join(
|
folder = os.path.join(
|
||||||
@@ -245,16 +249,16 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
timestr = time.strftime('%Y%m%d-%H%M%S')
|
timestr = time.strftime('%Y%m%d-%H%M%S')
|
||||||
out = os.path.join(folder, '{}.p'.format(timestr))
|
out = os.path.join(folder, '{}.p'.format(timestr))
|
||||||
# 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
|
# 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(
|
run_algorithm(
|
||||||
capital_base=10000,
|
capital_base=0.1,
|
||||||
data_frequency='minute',
|
data_frequency='minute',
|
||||||
initialize=initialize,
|
initialize=initialize,
|
||||||
handle_data=handle_data,
|
handle_data=handle_data,
|
||||||
analyze=analyze,
|
analyze=analyze,
|
||||||
exchange_name='bitfinex',
|
exchange_name='bitfinex',
|
||||||
algo_namespace=NAMESPACE,
|
algo_namespace=NAMESPACE,
|
||||||
base_currency='usd',
|
base_currency='eth',
|
||||||
start=pd.to_datetime('2017-10-01', utc=True),
|
start=pd.to_datetime('2017-10-01', utc=True),
|
||||||
end=pd.to_datetime('2017-11-10', utc=True),
|
end=pd.to_datetime('2017-11-10', utc=True),
|
||||||
output=out
|
output=out
|
||||||
@@ -263,7 +267,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
elif MODE == 'live':
|
elif MODE == 'live':
|
||||||
run_algorithm(
|
run_algorithm(
|
||||||
capital_base=0.5,
|
capital_base=0.1,
|
||||||
initialize=initialize,
|
initialize=initialize,
|
||||||
handle_data=handle_data,
|
handle_data=handle_data,
|
||||||
analyze=analyze,
|
analyze=analyze,
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
'''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
|
||||||
|
from scipy.optimize import minimize
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from catalyst.api import record, symbol, symbols, order_target_percent
|
||||||
|
from catalyst.utils.run_algo import run_algorithm
|
||||||
|
|
||||||
|
np.set_printoptions(threshold='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 beggining 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 xrange(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]
|
||||||
|
i = 0
|
||||||
|
for iw in weights:
|
||||||
|
results_array[3+i,p] = weights[i]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
#convert results array to Pandas DataFrame
|
||||||
|
results_frame = pd.DataFrame(np.transpose(results_array),
|
||||||
|
columns=['r','stdev','sharpe']+context.assets)
|
||||||
|
#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:
|
||||||
|
if data.can_trade(asset):
|
||||||
|
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 red star 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)
|
||||||
|
#plot green star to highlight position of minimum variance portfolio
|
||||||
|
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')
|
||||||
|
|
||||||
|
|
||||||
|
# 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, )
|
||||||
@@ -9,7 +9,7 @@ from catalyst.exchange.stats_utils import get_pretty_stats, \
|
|||||||
|
|
||||||
def initialize(context):
|
def initialize(context):
|
||||||
print('initializing')
|
print('initializing')
|
||||||
context.asset = symbol('neo_usd')
|
context.asset = symbol('neo_eth')
|
||||||
context.base_price = None
|
context.base_price = None
|
||||||
|
|
||||||
|
|
||||||
@@ -19,17 +19,14 @@ def handle_data(context, data):
|
|||||||
price = data.current(context.asset, 'close')
|
price = data.current(context.asset, 'close')
|
||||||
print('got price {price}'.format(price=price))
|
print('got price {price}'.format(price=price))
|
||||||
|
|
||||||
try:
|
|
||||||
prices = data.history(
|
prices = data.history(
|
||||||
context.asset,
|
context.asset,
|
||||||
fields='price',
|
fields='price',
|
||||||
bar_count=14,
|
bar_count=20,
|
||||||
frequency='15T'
|
frequency='15T'
|
||||||
)
|
)
|
||||||
rsi = talib.RSI(prices.values, timeperiod=14)[-1]
|
rsi = talib.RSI(prices.values, timeperiod=14)[-1]
|
||||||
print('got rsi: {}'.format(rsi))
|
print('got rsi: {}'.format(rsi))
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
# If base_price is not set, we use the current value. This is the
|
# 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.
|
# price at the first bar which we reference to calculate price_change.
|
||||||
@@ -126,8 +123,9 @@ run_algorithm(
|
|||||||
# initialize=initialize,
|
# initialize=initialize,
|
||||||
# handle_data=handle_data,
|
# handle_data=handle_data,
|
||||||
# analyze=None,
|
# analyze=None,
|
||||||
# exchange_name='poloniex',
|
# exchange_name='binance',
|
||||||
# live=True,
|
# live=True,
|
||||||
# algo_namespace='simple_loop',
|
# algo_namespace='simple_loop',
|
||||||
# base_currency='eth',
|
# base_currency='eth',
|
||||||
# live_graph=False
|
# live_graph=False,
|
||||||
|
# )
|
||||||
|
|||||||
@@ -0,0 +1,600 @@
|
|||||||
|
import re
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
import ccxt
|
||||||
|
import pandas as pd
|
||||||
|
from ccxt import ExchangeNotAvailable
|
||||||
|
from six import string_types
|
||||||
|
|
||||||
|
from catalyst.finance.order import Order, ORDER_STATUS
|
||||||
|
|
||||||
|
from catalyst.algorithm import MarketOrder
|
||||||
|
from catalyst.assets._assets import TradingPair
|
||||||
|
from logbook import Logger
|
||||||
|
|
||||||
|
from catalyst.constants import LOG_LEVEL
|
||||||
|
from catalyst.exchange.exchange import Exchange, ExchangeLimitOrder
|
||||||
|
from catalyst.exchange.exchange_bundle import ExchangeBundle
|
||||||
|
from catalyst.exchange.exchange_errors import InvalidHistoryFrequencyError, \
|
||||||
|
ExchangeSymbolsNotFound, ExchangeRequestError, InvalidOrderStyle, \
|
||||||
|
ExchangeNotFoundError
|
||||||
|
from catalyst.exchange.exchange_utils import mixin_market_params, \
|
||||||
|
from_ms_timestamp
|
||||||
|
|
||||||
|
log = Logger('CCXT', level=LOG_LEVEL)
|
||||||
|
|
||||||
|
SUPPORTED_EXCHANGES = dict(
|
||||||
|
binance=ccxt.binance,
|
||||||
|
bitfinex=ccxt.bitfinex,
|
||||||
|
bittrex=ccxt.bittrex,
|
||||||
|
poloniex=ccxt.poloniex,
|
||||||
|
bitmex=ccxt.bitmex,
|
||||||
|
gdax=ccxt.gdax,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CCXT(Exchange):
|
||||||
|
def __init__(self, exchange_name, key, secret, base_currency,
|
||||||
|
portfolio=None):
|
||||||
|
log.debug(
|
||||||
|
'finding {} in CCXT exchanges:\n{}'.format(
|
||||||
|
exchange_name, ccxt.exchanges
|
||||||
|
)
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
# Making instantiation as explicit as possible for code tracking.
|
||||||
|
if exchange_name in SUPPORTED_EXCHANGES:
|
||||||
|
exchange_attr = SUPPORTED_EXCHANGES[exchange_name]
|
||||||
|
|
||||||
|
else:
|
||||||
|
exchange_attr = getattr(ccxt, exchange_name)
|
||||||
|
|
||||||
|
self.api = exchange_attr({
|
||||||
|
'apiKey': key,
|
||||||
|
'secret': secret,
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
raise ExchangeNotFoundError(exchange_name=exchange_name)
|
||||||
|
|
||||||
|
self._symbol_maps = [None, None]
|
||||||
|
|
||||||
|
markets_symbols = self.api.load_markets()
|
||||||
|
log.debug('the markets:\n{}'.format(markets_symbols))
|
||||||
|
|
||||||
|
self.name = exchange_name
|
||||||
|
|
||||||
|
self.markets = self.api.fetch_markets()
|
||||||
|
self.load_assets()
|
||||||
|
|
||||||
|
self.base_currency = base_currency
|
||||||
|
self._portfolio = portfolio
|
||||||
|
self.transactions = defaultdict(list)
|
||||||
|
|
||||||
|
self.num_candles_limit = 2000
|
||||||
|
self.max_requests_per_minute = 60
|
||||||
|
self.request_cpt = dict()
|
||||||
|
|
||||||
|
self.bundle = ExchangeBundle(self.name)
|
||||||
|
|
||||||
|
def account(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def time_skew(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_market(self, symbol):
|
||||||
|
"""
|
||||||
|
The CCXT market.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
symbol:
|
||||||
|
The CCXT symbol.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict[str, Object]
|
||||||
|
|
||||||
|
"""
|
||||||
|
s = self.get_symbol(symbol)
|
||||||
|
market = next(
|
||||||
|
(market for market in self.markets if market['symbol'] == s),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
return market
|
||||||
|
|
||||||
|
def get_symbol(self, asset_or_symbol):
|
||||||
|
"""
|
||||||
|
The CCXT symbol.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
asset_or_symbol
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
|
symbol = asset_or_symbol if isinstance(
|
||||||
|
asset_or_symbol, string_types
|
||||||
|
) else asset_or_symbol.symbol
|
||||||
|
|
||||||
|
parts = symbol.split('_')
|
||||||
|
return '{}/{}'.format(parts[0].upper(), parts[1].upper())
|
||||||
|
|
||||||
|
def get_catalyst_symbol(self, market_or_symbol):
|
||||||
|
"""
|
||||||
|
The Catalyst symbol.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
market_or_symbol
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
|
if isinstance(market_or_symbol, string_types):
|
||||||
|
parts = market_or_symbol.split('/')
|
||||||
|
return '{}_{}'.format(parts[0].lower(), parts[1].lower())
|
||||||
|
|
||||||
|
else:
|
||||||
|
return '{}_{}'.format(
|
||||||
|
market_or_symbol['base'].lower(),
|
||||||
|
market_or_symbol['quote'].lower(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_timeframe(self, freq):
|
||||||
|
"""
|
||||||
|
The CCXT timeframe from the Catalyst frequency.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
freq: str
|
||||||
|
The Catalyst frequency (Pandas convention)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
|
||||||
|
"""
|
||||||
|
freq_match = re.match(r'([0-9].*)?(m|M|d|D|h|H|T)', freq, re.M | re.I)
|
||||||
|
if freq_match:
|
||||||
|
candle_size = int(freq_match.group(1)) \
|
||||||
|
if freq_match.group(1) else 1
|
||||||
|
|
||||||
|
unit = freq_match.group(2)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise InvalidHistoryFrequencyError(frequency=freq)
|
||||||
|
|
||||||
|
if unit.lower() == 'd':
|
||||||
|
timeframe = '{}d'.format(candle_size)
|
||||||
|
|
||||||
|
elif unit.lower() == 'm' or unit == 'T':
|
||||||
|
timeframe = '{}m'.format(candle_size)
|
||||||
|
|
||||||
|
elif unit.lower() == 'h' or unit == 'T':
|
||||||
|
timeframe = '{}h'.format(candle_size)
|
||||||
|
|
||||||
|
return timeframe
|
||||||
|
|
||||||
|
def get_candles(self, freq, assets, bar_count=None, start_dt=None,
|
||||||
|
end_dt=None):
|
||||||
|
symbols = self.get_symbols(assets)
|
||||||
|
timeframe = self.get_timeframe(freq)
|
||||||
|
delta = start_dt - pd.to_datetime('1970-1-1', utc=True)
|
||||||
|
ms = int(delta.total_seconds()) * 1000
|
||||||
|
|
||||||
|
candles = dict()
|
||||||
|
for asset in assets:
|
||||||
|
ohlcvs = self.api.fetch_ohlcv(
|
||||||
|
symbol=symbols[0],
|
||||||
|
timeframe=timeframe,
|
||||||
|
since=ms,
|
||||||
|
limit=bar_count,
|
||||||
|
params={}
|
||||||
|
)
|
||||||
|
|
||||||
|
candles[asset] = []
|
||||||
|
for ohlcv in ohlcvs:
|
||||||
|
candles[asset].append(dict(
|
||||||
|
last_traded=pd.to_datetime(ohlcv[0], unit='ms', utc=True),
|
||||||
|
open=ohlcv[1],
|
||||||
|
high=ohlcv[2],
|
||||||
|
low=ohlcv[3],
|
||||||
|
close=ohlcv[4],
|
||||||
|
volume=ohlcv[5]
|
||||||
|
))
|
||||||
|
|
||||||
|
return candles
|
||||||
|
|
||||||
|
def _fetch_symbol_map(self, is_local):
|
||||||
|
try:
|
||||||
|
return self.fetch_symbol_map(is_local)
|
||||||
|
except ExchangeSymbolsNotFound:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_asset_defs(self, market):
|
||||||
|
"""
|
||||||
|
The local and Catalyst definitions of the specified market.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
market: dict[str, Object]
|
||||||
|
The CCXT market dicts.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict[str, Object]
|
||||||
|
The asset definition.
|
||||||
|
|
||||||
|
"""
|
||||||
|
asset_defs = []
|
||||||
|
|
||||||
|
for is_local in (False, True):
|
||||||
|
asset_def = self.get_asset_def(market, is_local)
|
||||||
|
asset_defs.append((asset_def, is_local))
|
||||||
|
|
||||||
|
return asset_defs
|
||||||
|
|
||||||
|
def get_asset_def(self, market, is_local=False):
|
||||||
|
"""
|
||||||
|
The asset definition (in symbols.json files) corresponding
|
||||||
|
to the the specified market.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
market: dict[str, Object]
|
||||||
|
The CCXT market dict.
|
||||||
|
is_local
|
||||||
|
Whether to search in local or Catalyst asset definitions.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict[str, Object]
|
||||||
|
The asset definition.
|
||||||
|
|
||||||
|
"""
|
||||||
|
exchange_symbol = market['id']
|
||||||
|
|
||||||
|
symbol_map = self._fetch_symbol_map(is_local)
|
||||||
|
if symbol_map is not None:
|
||||||
|
assets_lower = {k.lower(): v for k, v in symbol_map.items()}
|
||||||
|
key = exchange_symbol.lower()
|
||||||
|
|
||||||
|
asset = assets_lower[key] if key in assets_lower else None
|
||||||
|
if asset is not None:
|
||||||
|
return asset
|
||||||
|
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def create_trading_pair(self, market, asset_def, is_local):
|
||||||
|
"""
|
||||||
|
Creating a TradingPair from market and asset data.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
market: dict[str, Object]
|
||||||
|
asset_def: dict[str, Object]
|
||||||
|
is_local: bool
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
|
data_source = 'local' if is_local else 'catalyst'
|
||||||
|
params = dict(
|
||||||
|
exchange=self.name,
|
||||||
|
data_source=data_source,
|
||||||
|
exchange_symbol=market['id'],
|
||||||
|
)
|
||||||
|
mixin_market_params(self.name, params, market)
|
||||||
|
|
||||||
|
if asset_def is not None:
|
||||||
|
params['symbol'] = asset_def['symbol']
|
||||||
|
|
||||||
|
params['start_date'] = asset_def['start_date'] \
|
||||||
|
if 'start_date' in asset_def else None
|
||||||
|
|
||||||
|
params['end_date'] = asset_def['end_date'] \
|
||||||
|
if 'end_date' in asset_def else None
|
||||||
|
|
||||||
|
params['leverage'] = asset_def['leverage'] \
|
||||||
|
if 'leverage' in asset_def else 1.0
|
||||||
|
|
||||||
|
params['asset_name'] = asset_def['asset_name'] \
|
||||||
|
if 'asset_name' in asset_def else None
|
||||||
|
|
||||||
|
params['end_daily'] = asset_def['end_daily'] \
|
||||||
|
if 'end_daily' in asset_def \
|
||||||
|
and asset_def['end_daily'] != 'N/A' else None
|
||||||
|
|
||||||
|
params['end_minute'] = asset_def['end_minute'] \
|
||||||
|
if 'end_minute' in asset_def \
|
||||||
|
and asset_def['end_minute'] != 'N/A' else None
|
||||||
|
|
||||||
|
else:
|
||||||
|
params['symbol'] = self.get_catalyst_symbol(market)
|
||||||
|
# TODO: add as an optional column
|
||||||
|
params['leverage'] = 1.0
|
||||||
|
|
||||||
|
return TradingPair(**params)
|
||||||
|
|
||||||
|
def load_assets(self):
|
||||||
|
self.assets = []
|
||||||
|
|
||||||
|
for market in self.markets:
|
||||||
|
asset_defs = self.get_asset_defs(market)
|
||||||
|
|
||||||
|
for asset_def in asset_defs:
|
||||||
|
if asset_def[0] is not None or not asset_defs[1]:
|
||||||
|
try:
|
||||||
|
asset = self.create_trading_pair(
|
||||||
|
market=market,
|
||||||
|
asset_def=asset_def[0],
|
||||||
|
is_local=asset_def[1]
|
||||||
|
)
|
||||||
|
self.assets.append(asset)
|
||||||
|
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_balances(self):
|
||||||
|
try:
|
||||||
|
log.debug('retrieving wallets balances')
|
||||||
|
balances = self.api.fetch_balance()
|
||||||
|
|
||||||
|
balances_lower = dict()
|
||||||
|
for key in balances:
|
||||||
|
balances_lower[key.lower()] = balances[key]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.debug('error retrieving balances: {}', e)
|
||||||
|
raise ExchangeRequestError(error=e)
|
||||||
|
|
||||||
|
return balances_lower
|
||||||
|
|
||||||
|
def _create_order(self, order_status):
|
||||||
|
"""
|
||||||
|
Create a Catalyst order object from a CCXT order dictionary
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
order_status: dict[str, Object]
|
||||||
|
The order dict from the CCXT api.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Order
|
||||||
|
The Catalyst order object
|
||||||
|
|
||||||
|
"""
|
||||||
|
if order_status['status'] == 'canceled':
|
||||||
|
status = ORDER_STATUS.CANCELLED
|
||||||
|
|
||||||
|
elif order_status['status'] == 'closed' and order_status['filled'] > 0:
|
||||||
|
log.debug('found executed order {}'.format(order_status))
|
||||||
|
status = ORDER_STATUS.FILLED
|
||||||
|
|
||||||
|
elif order_status['status'] == 'open':
|
||||||
|
status = ORDER_STATUS.OPEN
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ValueError('invalid state for order')
|
||||||
|
|
||||||
|
amount = order_status['amount']
|
||||||
|
filled = order_status['filled']
|
||||||
|
|
||||||
|
if order_status['side'] == 'sell':
|
||||||
|
amount = -amount
|
||||||
|
filled = -filled
|
||||||
|
|
||||||
|
price = order_status['price']
|
||||||
|
order_type = order_status['type']
|
||||||
|
|
||||||
|
limit_price = price if order_type == 'limit' else None
|
||||||
|
stop_price = None # TODO: add support
|
||||||
|
|
||||||
|
executed_price = order_status['cost'] / order_status['amount']
|
||||||
|
commission = order_status['fee']
|
||||||
|
date = from_ms_timestamp(order_status['timestamp'])
|
||||||
|
|
||||||
|
# order_id = str(order_status['info']['clientOrderId'])
|
||||||
|
order_id = order_status['id']
|
||||||
|
|
||||||
|
# TODO: this won't work, redo the packages with a different key.
|
||||||
|
symbol = order_status['info']['symbol'] \
|
||||||
|
if 'symbol' in order_status['info'] \
|
||||||
|
else order_status['info']['Exchange']
|
||||||
|
|
||||||
|
order = Order(
|
||||||
|
dt=date,
|
||||||
|
asset=self.get_asset(symbol, is_exchange_symbol=True),
|
||||||
|
amount=amount,
|
||||||
|
stop=stop_price,
|
||||||
|
limit=limit_price,
|
||||||
|
filled=filled,
|
||||||
|
id=order_id,
|
||||||
|
commission=commission
|
||||||
|
)
|
||||||
|
order.status = status
|
||||||
|
|
||||||
|
return order, executed_price
|
||||||
|
|
||||||
|
def create_order(self, asset, amount, is_buy, style):
|
||||||
|
symbol = self.get_symbol(asset)
|
||||||
|
|
||||||
|
if isinstance(style, ExchangeLimitOrder):
|
||||||
|
price = style.get_limit_price(is_buy)
|
||||||
|
order_type = 'limit'
|
||||||
|
|
||||||
|
elif isinstance(style, MarketOrder):
|
||||||
|
price = None
|
||||||
|
order_type = 'market'
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise InvalidOrderStyle(
|
||||||
|
exchange=self.name,
|
||||||
|
style=style.__class__.__name__
|
||||||
|
)
|
||||||
|
|
||||||
|
side = 'buy' if amount > 0 else 'sell'
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = self.api.create_order(
|
||||||
|
symbol=symbol,
|
||||||
|
type=order_type,
|
||||||
|
side=side,
|
||||||
|
amount=abs(amount),
|
||||||
|
price=price
|
||||||
|
)
|
||||||
|
except ExchangeNotAvailable as e:
|
||||||
|
log.debug('unable to create order: {}'.format(e))
|
||||||
|
raise ExchangeRequestError(error=e)
|
||||||
|
|
||||||
|
if 'info' not in result:
|
||||||
|
raise ValueError('cannot use order without info attribute')
|
||||||
|
|
||||||
|
order_id = result['id']
|
||||||
|
order = Order(
|
||||||
|
dt=pd.Timestamp.utcnow(),
|
||||||
|
asset=asset,
|
||||||
|
amount=amount,
|
||||||
|
stop=style.get_stop_price(is_buy),
|
||||||
|
limit=style.get_limit_price(is_buy),
|
||||||
|
id=order_id
|
||||||
|
)
|
||||||
|
return order
|
||||||
|
|
||||||
|
def get_open_orders(self, asset):
|
||||||
|
try:
|
||||||
|
symbol = self.get_symbol(asset)
|
||||||
|
result = self.api.fetch_open_orders(
|
||||||
|
symbol=symbol,
|
||||||
|
since=None,
|
||||||
|
limit=None,
|
||||||
|
params=dict()
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise ExchangeRequestError(error=e)
|
||||||
|
|
||||||
|
orders = []
|
||||||
|
for order_status in result:
|
||||||
|
order, executed_price = self._create_order(order_status)
|
||||||
|
if asset is None or asset == order.sid:
|
||||||
|
orders.append(order)
|
||||||
|
|
||||||
|
return orders
|
||||||
|
|
||||||
|
def _get_asset_from_order(self, order_id):
|
||||||
|
open_orders = self.portfolio.open_orders
|
||||||
|
order = next(
|
||||||
|
(open_orders[id] for id in open_orders if id == order_id),
|
||||||
|
None
|
||||||
|
) # type: Order
|
||||||
|
return order.asset if order is not None else None
|
||||||
|
|
||||||
|
def get_order(self, order_id, asset_or_symbol=None):
|
||||||
|
if asset_or_symbol is None and self.portfolio is not None:
|
||||||
|
asset_or_symbol = self._get_asset_from_order(order_id)
|
||||||
|
|
||||||
|
if asset_or_symbol is None:
|
||||||
|
log.debug(
|
||||||
|
'order not found in memory, the request might fail '
|
||||||
|
'on some exchanges.'
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
symbol = self.get_symbol(asset_or_symbol) \
|
||||||
|
if asset_or_symbol is not None else None
|
||||||
|
order_status = self.api.fetch_order(id=order_id, symbol=symbol)
|
||||||
|
order, executed_price = self._create_order(order_status)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise ExchangeRequestError(error=e)
|
||||||
|
|
||||||
|
return order, executed_price
|
||||||
|
|
||||||
|
def cancel_order(self, order_param, asset_or_symbol=None):
|
||||||
|
order_id = order_param.id \
|
||||||
|
if isinstance(order_param, Order) else order_param
|
||||||
|
|
||||||
|
if asset_or_symbol is None and self.portfolio is not None:
|
||||||
|
asset_or_symbol = self._get_asset_from_order(order_id)
|
||||||
|
|
||||||
|
if asset_or_symbol is None:
|
||||||
|
log.debug(
|
||||||
|
'order not found in memory, cancelling order might fail '
|
||||||
|
'on some exchanges.'
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
symbol = self.get_symbol(asset_or_symbol) \
|
||||||
|
if asset_or_symbol is not None else None
|
||||||
|
self.api.cancel_order(id=order_id, symbol=symbol)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise ExchangeRequestError(error=e)
|
||||||
|
|
||||||
|
def tickers(self, assets):
|
||||||
|
"""
|
||||||
|
Retrieve current tick data for the given assets
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
assets: list[TradingPair]
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[dict[str, float]
|
||||||
|
|
||||||
|
"""
|
||||||
|
tickers = dict()
|
||||||
|
for asset in assets:
|
||||||
|
ccxt_symbol = self.get_symbol(asset)
|
||||||
|
ticker = self.api.fetch_ticker(ccxt_symbol)
|
||||||
|
|
||||||
|
ticker['last_traded'] = from_ms_timestamp(ticker['timestamp'])
|
||||||
|
|
||||||
|
if 'last_price' not in ticker:
|
||||||
|
# TODO: any more exceptions?
|
||||||
|
ticker['last_price'] = ticker['last']
|
||||||
|
|
||||||
|
# Using the volume represented in the base currency
|
||||||
|
ticker['volume'] = ticker['baseVolume'] \
|
||||||
|
if 'baseVolume' in ticker else 0
|
||||||
|
|
||||||
|
tickers[asset] = ticker
|
||||||
|
|
||||||
|
return tickers
|
||||||
|
|
||||||
|
def get_account(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_orderbook(self, asset, order_type='all', limit=None):
|
||||||
|
ccxt_symbol = self.get_symbol(asset)
|
||||||
|
|
||||||
|
params = dict()
|
||||||
|
if limit is not None:
|
||||||
|
params['depth'] = limit
|
||||||
|
|
||||||
|
order_book = self.api.fetch_order_book(ccxt_symbol, params)
|
||||||
|
|
||||||
|
order_types = ['bids', 'asks'] if order_type == 'all' else [order_type]
|
||||||
|
result = dict(last_traded=from_ms_timestamp(order_book['timestamp']))
|
||||||
|
for index, order_type in enumerate(order_types):
|
||||||
|
if limit is not None and index > limit - 1:
|
||||||
|
break
|
||||||
|
|
||||||
|
result[order_type] = []
|
||||||
|
for entry in order_book[order_type]:
|
||||||
|
result[order_type].append(dict(
|
||||||
|
rate=float(entry[0]),
|
||||||
|
quantity=float(entry[1])
|
||||||
|
))
|
||||||
|
|
||||||
|
return result
|
||||||
+116
-121
@@ -8,15 +8,16 @@ import pandas as pd
|
|||||||
from catalyst.assets._assets import TradingPair
|
from catalyst.assets._assets import TradingPair
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
|
|
||||||
|
from catalyst.algorithm import MarketOrder
|
||||||
from catalyst.constants import LOG_LEVEL
|
from catalyst.constants import LOG_LEVEL
|
||||||
from catalyst.data.data_portal import BASE_FIELDS
|
from catalyst.data.data_portal import BASE_FIELDS
|
||||||
from catalyst.exchange.bundle_utils import get_start_dt, \
|
from catalyst.exchange.bundle_utils import get_start_dt, \
|
||||||
get_delta, get_periods, get_periods_range
|
get_delta, get_periods, get_periods_range
|
||||||
from catalyst.exchange.exchange_bundle import ExchangeBundle
|
from catalyst.exchange.exchange_bundle import ExchangeBundle
|
||||||
from catalyst.exchange.exchange_errors import MismatchingBaseCurrencies, \
|
from catalyst.exchange.exchange_errors import MismatchingBaseCurrencies, \
|
||||||
InvalidOrderStyle, BaseCurrencyNotFoundError, SymbolNotFoundOnExchange, \
|
BaseCurrencyNotFoundError, SymbolNotFoundOnExchange, \
|
||||||
PricingDataNotLoadedError, \
|
PricingDataNotLoadedError, \
|
||||||
NoDataAvailableOnExchange, ExchangeSymbolsNotFound
|
NoDataAvailableOnExchange, NoValueForField
|
||||||
from catalyst.exchange.exchange_execution import ExchangeStopLimitOrder, \
|
from catalyst.exchange.exchange_execution import ExchangeStopLimitOrder, \
|
||||||
ExchangeLimitOrder, ExchangeStopOrder
|
ExchangeLimitOrder, ExchangeStopOrder
|
||||||
from catalyst.exchange.exchange_portfolio import ExchangePortfolio
|
from catalyst.exchange.exchange_portfolio import ExchangePortfolio
|
||||||
@@ -33,8 +34,8 @@ class Exchange:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.name = None
|
self.name = None
|
||||||
self.assets = dict()
|
self.assets = []
|
||||||
self.local_assets = dict()
|
self._symbol_maps = [None, None]
|
||||||
self._portfolio = None
|
self._portfolio = None
|
||||||
self.minute_writer = None
|
self.minute_writer = None
|
||||||
self.minute_reader = None
|
self.minute_reader = None
|
||||||
@@ -145,9 +146,9 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
symbol = None
|
symbol = None
|
||||||
|
|
||||||
for key in self.assets:
|
for a in self.assets:
|
||||||
if not symbol and self.assets[key].symbol == asset.symbol:
|
if not symbol and a.symbol == asset.symbol:
|
||||||
symbol = key
|
symbol = a.symbol
|
||||||
|
|
||||||
if not symbol:
|
if not symbol:
|
||||||
raise ValueError('Currency %s not supported by exchange %s' %
|
raise ValueError('Currency %s not supported by exchange %s' %
|
||||||
@@ -174,72 +175,103 @@ class Exchange:
|
|||||||
|
|
||||||
return symbols
|
return symbols
|
||||||
|
|
||||||
def get_assets(self, symbols=None, data_frequency=None):
|
def get_assets(self, symbols=None, data_frequency=None,
|
||||||
|
is_exchange_symbol=False,
|
||||||
|
is_local=None):
|
||||||
"""
|
"""
|
||||||
The list of markets for the specified symbols.
|
The list of markets for the specified symbols.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
symbols: list[str]
|
symbols: list[str]
|
||||||
|
data_frequency: str
|
||||||
|
is_exchange_symbol: bool
|
||||||
|
is_local: bool
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
list[TradingPair]
|
list[TradingPair]
|
||||||
|
A list of asset objects.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
See get_asset for details of each parameter.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if symbols is None:
|
||||||
|
# Make a distinct list of all symbols
|
||||||
|
symbols = list(set([asset.symbol for asset in self.assets]))
|
||||||
|
is_exchange_symbol = False
|
||||||
|
|
||||||
assets = []
|
assets = []
|
||||||
|
|
||||||
if symbols is not None:
|
|
||||||
for symbol in symbols:
|
for symbol in symbols:
|
||||||
asset = self.get_asset(symbol, data_frequency)
|
asset = self.get_asset(
|
||||||
|
symbol, data_frequency, is_exchange_symbol, is_local
|
||||||
|
)
|
||||||
assets.append(asset)
|
assets.append(asset)
|
||||||
else:
|
|
||||||
for key in self.assets:
|
|
||||||
assets.append(self.assets[key])
|
|
||||||
|
|
||||||
return assets
|
return assets
|
||||||
|
|
||||||
def _find_asset(self, asset, symbol, data_frequency, is_local=False):
|
def get_asset(self, symbol, data_frequency=None, is_exchange_symbol=False,
|
||||||
assets = self.assets if not is_local else self.local_assets
|
is_local=None):
|
||||||
|
|
||||||
for key in assets:
|
|
||||||
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
|
|
||||||
|
|
||||||
def get_asset(self, symbol, data_frequency=None):
|
|
||||||
"""
|
"""
|
||||||
The market for the specified symbol.
|
The market for the specified symbol.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
symbol: str
|
symbol: str
|
||||||
|
The Catalyst or exchange symbol.
|
||||||
|
|
||||||
|
data_frequency: str
|
||||||
|
Check for asset corresponding to the specified data_frequency.
|
||||||
|
The same asset might exist in the Catalyst repository or
|
||||||
|
locally (following a CSV ingestion). Filtering by
|
||||||
|
data_frequency picks the right asset.
|
||||||
|
|
||||||
|
is_exchange_symbol: bool
|
||||||
|
Whether the symbol uses the Catalyst or exchange convention.
|
||||||
|
|
||||||
|
is_local: bool
|
||||||
|
For the local or Catalyst asset.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
TradingPair
|
TradingPair
|
||||||
|
The asset object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
asset = None
|
asset = None
|
||||||
|
|
||||||
log.debug('searching asset {} on the server'.format(symbol))
|
log.debug(
|
||||||
asset = self._find_asset(asset, symbol, data_frequency, False)
|
'searching assets for: {} {}'.format(
|
||||||
|
self.name, symbol
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for a in self.assets:
|
||||||
|
if asset is not None:
|
||||||
|
break
|
||||||
|
|
||||||
log.debug('asset {} not found on the server, searching local '
|
if is_local is not None:
|
||||||
'assets'.format(symbol))
|
data_source = 'local' if is_local else 'catalyst'
|
||||||
asset = self._find_asset(asset, symbol, data_frequency, True)
|
applies = (a.data_source == data_source)
|
||||||
|
|
||||||
if not asset:
|
elif data_frequency is not None:
|
||||||
all_values = list(self.assets.values()) + \
|
applies = (
|
||||||
list(self.local_assets.values())
|
(data_frequency == 'minute' and a.end_minute is not None)
|
||||||
|
or (data_frequency == 'daily' and a.end_daily is not None)
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
applies = True
|
||||||
|
|
||||||
|
# The symbol provided may use the Catalyst or the exchange
|
||||||
|
# convention
|
||||||
|
key = a.exchange_symbol if is_exchange_symbol else a.symbol
|
||||||
|
if not asset and key.lower() == symbol.lower() and applies:
|
||||||
|
asset = a
|
||||||
|
|
||||||
|
if asset is None:
|
||||||
supported_symbols = sorted([
|
supported_symbols = sorted([
|
||||||
asset.symbol for asset in all_values
|
asset.symbol for asset in self.assets
|
||||||
])
|
])
|
||||||
|
|
||||||
raise SymbolNotFoundOnExchange(
|
raise SymbolNotFoundOnExchange(
|
||||||
@@ -248,11 +280,20 @@ class Exchange:
|
|||||||
supported_symbols=supported_symbols
|
supported_symbols=supported_symbols
|
||||||
)
|
)
|
||||||
|
|
||||||
|
log.debug('found asset: {}'.format(asset))
|
||||||
return asset
|
return asset
|
||||||
|
|
||||||
def fetch_symbol_map(self, is_local=False):
|
def fetch_symbol_map(self, is_local=False):
|
||||||
return get_exchange_symbols(self.name, is_local)
|
index = 1 if is_local else 0
|
||||||
|
if self._symbol_maps[index] is not None:
|
||||||
|
return self._symbol_maps[index]
|
||||||
|
|
||||||
|
else:
|
||||||
|
symbol_map = get_exchange_symbols(self.name, is_local)
|
||||||
|
self._symbol_maps[index] = symbol_map
|
||||||
|
return symbol_map
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
def load_assets(self, is_local=False):
|
def load_assets(self, is_local=False):
|
||||||
"""
|
"""
|
||||||
Populate the 'assets' attribute with a dictionary of Assets.
|
Populate the 'assets' attribute with a dictionary of Assets.
|
||||||
@@ -270,66 +311,7 @@ class Exchange:
|
|||||||
via its api.
|
via its api.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
pass
|
||||||
symbol_map = self.fetch_symbol_map(is_local)
|
|
||||||
except ExchangeSymbolsNotFound:
|
|
||||||
return None
|
|
||||||
|
|
||||||
for exchange_symbol in symbol_map:
|
|
||||||
asset = symbol_map[exchange_symbol]
|
|
||||||
|
|
||||||
if 'start_date' in asset:
|
|
||||||
start_date = pd.to_datetime(asset['start_date'], utc=True)
|
|
||||||
else:
|
|
||||||
start_date = None
|
|
||||||
|
|
||||||
if 'end_date' in asset:
|
|
||||||
end_date = pd.to_datetime(asset['end_date'], utc=True)
|
|
||||||
else:
|
|
||||||
end_date = None
|
|
||||||
|
|
||||||
if 'leverage' in asset:
|
|
||||||
leverage = asset['leverage']
|
|
||||||
else:
|
|
||||||
leverage = 1.0
|
|
||||||
|
|
||||||
if 'asset_name' in asset:
|
|
||||||
asset_name = asset['asset_name']
|
|
||||||
else:
|
|
||||||
asset_name = None
|
|
||||||
|
|
||||||
if 'min_trade_size' in asset:
|
|
||||||
min_trade_size = asset['min_trade_size']
|
|
||||||
else:
|
|
||||||
min_trade_size = 0.0000001
|
|
||||||
|
|
||||||
if 'end_daily' in asset and asset['end_daily'] != 'N/A':
|
|
||||||
end_daily = pd.to_datetime(asset['end_daily'], utc=True)
|
|
||||||
else:
|
|
||||||
end_daily = None
|
|
||||||
|
|
||||||
if 'end_minute' in asset and asset['end_minute'] != 'N/A':
|
|
||||||
end_minute = pd.to_datetime(asset['end_minute'], utc=True)
|
|
||||||
else:
|
|
||||||
end_minute = None
|
|
||||||
|
|
||||||
trading_pair = TradingPair(
|
|
||||||
symbol=asset['symbol'],
|
|
||||||
exchange=self.name,
|
|
||||||
start_date=start_date,
|
|
||||||
end_date=end_date,
|
|
||||||
leverage=leverage,
|
|
||||||
asset_name=asset_name,
|
|
||||||
min_trade_size=min_trade_size,
|
|
||||||
end_daily=end_daily,
|
|
||||||
end_minute=end_minute,
|
|
||||||
exchange_symbol=exchange_symbol
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_local:
|
|
||||||
self.local_assets[exchange_symbol] = trading_pair
|
|
||||||
else:
|
|
||||||
self.assets[exchange_symbol] = trading_pair
|
|
||||||
|
|
||||||
def check_open_orders(self):
|
def check_open_orders(self):
|
||||||
"""
|
"""
|
||||||
@@ -348,9 +330,11 @@ class Exchange:
|
|||||||
log.debug('found open order: {}'.format(order_id))
|
log.debug('found open order: {}'.format(order_id))
|
||||||
|
|
||||||
order, executed_price = self.get_order(order_id)
|
order, executed_price = self.get_order(order_id)
|
||||||
log.debug('got updated order {} {}'.format(
|
log.debug(
|
||||||
order, executed_price))
|
'got updated order {} {}'.format(
|
||||||
|
order, executed_price
|
||||||
|
)
|
||||||
|
)
|
||||||
if order.status == ORDER_STATUS.FILLED:
|
if order.status == ORDER_STATUS.FILLED:
|
||||||
transaction = Transaction(
|
transaction = Transaction(
|
||||||
asset=order.asset,
|
asset=order.asset,
|
||||||
@@ -412,12 +396,15 @@ class Exchange:
|
|||||||
if field not in BASE_FIELDS:
|
if field not in BASE_FIELDS:
|
||||||
raise KeyError('Invalid column: {}'.format(field))
|
raise KeyError('Invalid column: {}'.format(field))
|
||||||
|
|
||||||
values = []
|
tickers = self.tickers(assets)
|
||||||
for asset in assets:
|
if field == 'close' or field == 'price':
|
||||||
value = self.get_single_spot_value(asset, field, data_frequency)
|
return [tickers[asset]['last'] for asset in tickers]
|
||||||
values.append(value)
|
|
||||||
|
|
||||||
return values
|
elif field == 'volume':
|
||||||
|
return [tickers[asset]['volume'] for asset in tickers]
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise NoValueForField(field=field)
|
||||||
|
|
||||||
def get_single_spot_value(self, asset, field, data_frequency):
|
def get_single_spot_value(self, asset, field, data_frequency):
|
||||||
"""
|
"""
|
||||||
@@ -691,7 +678,7 @@ class Exchange:
|
|||||||
log.debug('synchronizing portfolio with exchange {}'.format(self.name))
|
log.debug('synchronizing portfolio with exchange {}'.format(self.name))
|
||||||
balances = self.get_balances()
|
balances = self.get_balances()
|
||||||
|
|
||||||
base_position_available = balances[self.base_currency] \
|
base_position_available = balances[self.base_currency]['free'] \
|
||||||
if self.base_currency in balances else None
|
if self.base_currency in balances else None
|
||||||
|
|
||||||
if base_position_available is None:
|
if base_position_available is None:
|
||||||
@@ -716,8 +703,9 @@ class Exchange:
|
|||||||
# TODO: convert if the position is not in the base currency
|
# TODO: convert if the position is not in the base currency
|
||||||
ticker = tickers[asset]
|
ticker = tickers[asset]
|
||||||
position = portfolio.positions[asset]
|
position = portfolio.positions[asset]
|
||||||
|
|
||||||
position.last_sale_price = ticker['last_price']
|
position.last_sale_price = ticker['last_price']
|
||||||
position.last_sale_date = ticker['timestamp']
|
position.last_sale_date = ticker['last_traded']
|
||||||
|
|
||||||
portfolio.positions_value += \
|
portfolio.positions_value += \
|
||||||
position.amount * position.last_sale_price
|
position.amount * position.last_sale_price
|
||||||
@@ -774,28 +762,30 @@ class Exchange:
|
|||||||
log.warn('skipping order amount of 0')
|
log.warn('skipping order amount of 0')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if asset.base_currency != self.base_currency.lower():
|
if self.base_currency is None:
|
||||||
|
raise ValueError('no base_currency defined for this exchange')
|
||||||
|
|
||||||
|
if asset.quote_currency != self.base_currency.lower():
|
||||||
raise MismatchingBaseCurrencies(
|
raise MismatchingBaseCurrencies(
|
||||||
base_currency=asset.base_currency,
|
base_currency=asset.quote_currency,
|
||||||
algo_currency=self.base_currency
|
algo_currency=self.base_currency
|
||||||
)
|
)
|
||||||
|
|
||||||
is_buy = (amount > 0)
|
is_buy = (amount > 0)
|
||||||
|
|
||||||
if limit_price is not None and stop_price is not None:
|
if limit_price is not None and stop_price is not None:
|
||||||
style = ExchangeStopLimitOrder(limit_price, stop_price,
|
style = ExchangeStopLimitOrder(
|
||||||
exchange=self.name)
|
limit_price, stop_price, exchange=self.name
|
||||||
|
)
|
||||||
|
|
||||||
elif limit_price is not None:
|
elif limit_price is not None:
|
||||||
style = ExchangeLimitOrder(limit_price, exchange=self.name)
|
style = ExchangeLimitOrder(limit_price, exchange=self.name)
|
||||||
|
|
||||||
elif stop_price is not None:
|
elif stop_price is not None:
|
||||||
style = ExchangeStopOrder(stop_price, exchange=self.name)
|
style = ExchangeStopOrder(stop_price, exchange=self.name)
|
||||||
|
|
||||||
elif style is not None:
|
|
||||||
raise InvalidOrderStyle(exchange=self.name.title(),
|
|
||||||
style=style.__class__.__name__)
|
|
||||||
else:
|
else:
|
||||||
raise ValueError('Incomplete order data.')
|
style = MarketOrder(exchange=self.name)
|
||||||
|
|
||||||
display_price = limit_price if limit_price is not None else stop_price
|
display_price = limit_price if limit_price is not None else stop_price
|
||||||
log.debug(
|
log.debug(
|
||||||
@@ -804,9 +794,10 @@ class Exchange:
|
|||||||
amount=amount,
|
amount=amount,
|
||||||
symbol=asset.symbol,
|
symbol=asset.symbol,
|
||||||
type=style.__class__.__name__,
|
type=style.__class__.__name__,
|
||||||
price='{}{}'.format(display_price, asset.base_currency)
|
price='{}{}'.format(display_price, asset.quote_currency)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
order = self.create_order(asset, amount, is_buy, style)
|
order = self.create_order(asset, amount, is_buy, style)
|
||||||
if order:
|
if order:
|
||||||
self._portfolio.create_order(order)
|
self._portfolio.create_order(order)
|
||||||
@@ -875,7 +866,7 @@ class Exchange:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_order(self, order_id):
|
def get_order(self, order_id, symbol_or_asset=None):
|
||||||
"""Lookup an order based on the order id returned from one of the
|
"""Lookup an order based on the order id returned from one of the
|
||||||
order functions.
|
order functions.
|
||||||
|
|
||||||
@@ -883,6 +874,8 @@ class Exchange:
|
|||||||
----------
|
----------
|
||||||
order_id : str
|
order_id : str
|
||||||
The unique identifier for the order.
|
The unique identifier for the order.
|
||||||
|
symbol_or_asset: str|TradingPair
|
||||||
|
The catalyst symbol, some exchanges need this
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@@ -894,13 +887,15 @@ class Exchange:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def cancel_order(self, order_param):
|
def cancel_order(self, order_param, symbol_or_asset=None):
|
||||||
"""Cancel an open order.
|
"""Cancel an open order.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
order_param : str or Order
|
order_param : str or Order
|
||||||
The order_id or order object to cancel.
|
The order_id or order object to cancel.
|
||||||
|
symbol_or_asset: str|TradingPair
|
||||||
|
The catalyst symbol, some exchanges need this
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.algo_namespace = kwargs.pop('algo_namespace', None)
|
self.algo_namespace = kwargs.pop('algo_namespace', None)
|
||||||
self.live_graph = kwargs.pop('live_graph', None)
|
self.live_graph = kwargs.pop('live_graph', None)
|
||||||
|
self.simulate_orders = kwargs.pop('simulate_orders', None)
|
||||||
|
|
||||||
self._clock = None
|
self._clock = None
|
||||||
self.frame_stats = deque(maxlen=60)
|
self.frame_stats = deque(maxlen=60)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import os
|
|
||||||
import shutil
|
import shutil
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from functools import partial
|
from functools import partial
|
||||||
@@ -28,10 +27,9 @@ from catalyst.exchange.exchange_bcolz import BcolzExchangeBarReader, \
|
|||||||
from catalyst.exchange.exchange_errors import EmptyValuesInBundleError, \
|
from catalyst.exchange.exchange_errors import EmptyValuesInBundleError, \
|
||||||
TempBundleNotFoundError, \
|
TempBundleNotFoundError, \
|
||||||
NoDataAvailableOnExchange, \
|
NoDataAvailableOnExchange, \
|
||||||
PricingDataNotLoadedError, DataCorruptionError, ExchangeSymbolsNotFound, \
|
PricingDataNotLoadedError, DataCorruptionError, PricingDataValueError
|
||||||
PricingDataValueError
|
|
||||||
from catalyst.exchange.exchange_utils import get_exchange_folder, \
|
from catalyst.exchange.exchange_utils import get_exchange_folder, \
|
||||||
get_exchange_symbols, save_exchange_symbols
|
save_exchange_symbols, mixin_market_params
|
||||||
from catalyst.utils.cli import maybe_show_progress
|
from catalyst.utils.cli import maybe_show_progress
|
||||||
from catalyst.utils.paths import ensure_directory
|
from catalyst.utils.paths import ensure_directory
|
||||||
|
|
||||||
@@ -667,12 +665,11 @@ class ExchangeBundle:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
log.info('ingesting csv file: {}'.format(path))
|
log.info('ingesting csv file: {}'.format(path))
|
||||||
try:
|
|
||||||
symbols_def = get_exchange_symbols(
|
if self.exchange is None:
|
||||||
self.exchange_name, is_local=True
|
# Avoid circular dependencies
|
||||||
)
|
from catalyst.exchange.factory import get_exchange
|
||||||
except ExchangeSymbolsNotFound:
|
self.exchange = get_exchange(self.exchange_name)
|
||||||
symbols_def = dict()
|
|
||||||
|
|
||||||
problems = []
|
problems = []
|
||||||
df = pd.read_csv(
|
df = pd.read_csv(
|
||||||
@@ -705,24 +702,40 @@ class ExchangeBundle:
|
|||||||
end_dt = df.index.get_level_values(1).max()
|
end_dt = df.index.get_level_values(1).max()
|
||||||
end_dt_key = 'end_{}'.format(data_frequency)
|
end_dt_key = 'end_{}'.format(data_frequency)
|
||||||
|
|
||||||
if symbol is symbols_def:
|
market = self.exchange.get_market(symbol)
|
||||||
symbol_def = symbols_def[symbol]
|
if market is None:
|
||||||
|
raise ValueError('symbol not available in the exchange.')
|
||||||
|
|
||||||
start_dt = symbol_def['start_date'] \
|
params = dict(
|
||||||
if symbol_def['start_date'] < start_dt else start_dt
|
exchange=self.exchange.name,
|
||||||
|
data_source='local',
|
||||||
|
exchange_symbol=market['id'],
|
||||||
|
)
|
||||||
|
mixin_market_params(self.exchange_name, params, market)
|
||||||
|
|
||||||
end_dt = symbol_def[end_dt_key] \
|
asset_def = self.exchange.get_asset_def(market, True)
|
||||||
if symbol_def[end_dt_key] > end_dt else end_dt
|
if asset_def is not None:
|
||||||
|
params['symbol'] = asset_def['symbol']
|
||||||
|
|
||||||
end_daily = end_dt \
|
params['start_date'] = asset_def['start_date'] \
|
||||||
if data_frequency == 'daily' else symbol_def['end_daily']
|
if asset_def['start_date'] < start_dt else start_dt
|
||||||
|
|
||||||
end_minute = end_dt \
|
params['end_date'] = asset_def[end_dt_key] \
|
||||||
if data_frequency == 'minute' else symbol_def['end_minute']
|
if asset_def[end_dt_key] > end_dt else end_dt
|
||||||
|
|
||||||
|
params['end_daily'] = end_dt \
|
||||||
|
if data_frequency == 'daily' else asset_def['end_daily']
|
||||||
|
|
||||||
|
params['end_minute'] = end_dt \
|
||||||
|
if data_frequency == 'minute' else asset_def['end_minute']
|
||||||
|
|
||||||
else:
|
else:
|
||||||
end_daily = end_dt if data_frequency == 'daily' else 'N/A'
|
params['symbol'] = self.exchange.get_catalyst_symbol(market)
|
||||||
end_minute = end_dt if data_frequency == 'minute' else 'N/A'
|
|
||||||
|
params['end_daily'] = end_dt \
|
||||||
|
if data_frequency == 'daily' else 'N/A'
|
||||||
|
params['end_minute'] = end_dt \
|
||||||
|
if data_frequency == 'minute' else 'N/A'
|
||||||
|
|
||||||
if min_start_dt is None or start_dt < min_start_dt:
|
if min_start_dt is None or start_dt < min_start_dt:
|
||||||
min_start_dt = start_dt
|
min_start_dt = start_dt
|
||||||
@@ -730,19 +743,8 @@ class ExchangeBundle:
|
|||||||
if max_end_dt is None or end_dt > max_end_dt:
|
if max_end_dt is None or end_dt > max_end_dt:
|
||||||
max_end_dt = end_dt
|
max_end_dt = end_dt
|
||||||
|
|
||||||
asset = TradingPair(
|
asset = TradingPair(**params)
|
||||||
symbol=symbol,
|
assets[market['id']] = asset
|
||||||
exchange=self.exchange_name,
|
|
||||||
start_date=start_dt,
|
|
||||||
end_date=end_dt,
|
|
||||||
leverage=0, # TODO: add as an optional column
|
|
||||||
asset_name=symbol,
|
|
||||||
min_trade_size=0, # TODO: add as an optional column
|
|
||||||
end_daily=end_daily,
|
|
||||||
end_minute=end_minute,
|
|
||||||
exchange_symbol=symbol
|
|
||||||
)
|
|
||||||
assets[symbol] = asset
|
|
||||||
|
|
||||||
save_exchange_symbols(self.exchange_name, assets, True)
|
save_exchange_symbols(self.exchange_name, assets, True)
|
||||||
|
|
||||||
|
|||||||
@@ -240,3 +240,7 @@ class NoDataAvailableOnExchange(ZiplineError):
|
|||||||
'Requested data for trading pair {symbol} is not available on exchange {exchange} '
|
'Requested data for trading pair {symbol} is not available on exchange {exchange} '
|
||||||
'in `{data_frequency}` frequency at this time. '
|
'in `{data_frequency}` frequency at this time. '
|
||||||
'Check `http://enigma.co/catalyst/status` for market coverage.').strip()
|
'Check `http://enigma.co/catalyst/status` for market coverage.').strip()
|
||||||
|
|
||||||
|
|
||||||
|
class NoValueForField(ZiplineError):
|
||||||
|
msg = ('Value not found for field: {field}.').strip()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from catalyst.finance.execution import LimitOrder, StopOrder, StopLimitOrder
|
from catalyst.finance.execution import LimitOrder, StopOrder, StopLimitOrder, MarketOrder
|
||||||
|
|
||||||
|
|
||||||
class ExchangeLimitOrder(LimitOrder):
|
class ExchangeLimitOrder(LimitOrder):
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from logbook import Logger
|
|||||||
|
|
||||||
from catalyst.constants import LOG_LEVEL
|
from catalyst.constants import LOG_LEVEL
|
||||||
from catalyst.protocol import Portfolio, Positions, Position
|
from catalyst.protocol import Portfolio, Positions, Position
|
||||||
from catalyst.utils.deprecate import deprecated
|
|
||||||
|
|
||||||
log = Logger('ExchangePortfolio', level=LOG_LEVEL)
|
log = Logger('ExchangePortfolio', level=LOG_LEVEL)
|
||||||
|
|
||||||
@@ -11,7 +10,8 @@ log = Logger('ExchangePortfolio', level=LOG_LEVEL)
|
|||||||
class ExchangePortfolio(Portfolio):
|
class ExchangePortfolio(Portfolio):
|
||||||
"""
|
"""
|
||||||
Since the goal is to support multiple exchanges, it makes sense to
|
Since the goal is to support multiple exchanges, it makes sense to
|
||||||
include additional stats in the portfolio object.
|
include additional stats in the portfolio object. This fills the role
|
||||||
|
of Blotter and Portfolio in live mode.
|
||||||
|
|
||||||
Instead of relying on the performance tracker, each exchange portfolio
|
Instead of relying on the performance tracker, each exchange portfolio
|
||||||
tracks its own holding. This offers a separation between tracking an
|
tracks its own holding. This offers a separation between tracking an
|
||||||
@@ -89,32 +89,6 @@ class ExchangePortfolio(Portfolio):
|
|||||||
|
|
||||||
log.debug('updated portfolio with executed order')
|
log.debug('updated portfolio with executed order')
|
||||||
|
|
||||||
@deprecated
|
|
||||||
def execute_transaction(self, transaction):
|
|
||||||
# TODO: almost duplicate of execute_order. Not sure why Poloniex needs this.
|
|
||||||
log.debug('executing transaction {}'.format(transaction.order_id))
|
|
||||||
|
|
||||||
order_position = self.positions[transaction.asset] \
|
|
||||||
if transaction.asset in self.positions else None
|
|
||||||
|
|
||||||
if order_position is None:
|
|
||||||
raise ValueError(
|
|
||||||
'Trying to execute transaction for a position not held: %s' % transaction.order_id
|
|
||||||
)
|
|
||||||
|
|
||||||
self.capital_used += transaction.amount * transaction.price
|
|
||||||
|
|
||||||
if transaction.amount > 0:
|
|
||||||
if order_position.cost_basis > 0:
|
|
||||||
order_position.cost_basis = np.average(
|
|
||||||
[order_position.cost_basis, transaction.price],
|
|
||||||
weights=[order_position.amount, transaction.amount]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
order_position.cost_basis = transaction.price
|
|
||||||
|
|
||||||
log.debug('updated portfolio with executed order')
|
|
||||||
|
|
||||||
def remove_order(self, order):
|
def remove_order(self, order):
|
||||||
"""
|
"""
|
||||||
Removing an open order.
|
Removing an open order.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from datetime import date, datetime
|
|||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from catalyst.assets._assets import TradingPair
|
from catalyst.assets._assets import TradingPair
|
||||||
|
from six import string_types
|
||||||
from six.moves.urllib import request
|
from six.moves.urllib import request
|
||||||
|
|
||||||
from catalyst.constants import DATE_FORMAT, SYMBOLS_URL
|
from catalyst.constants import DATE_FORMAT, SYMBOLS_URL
|
||||||
@@ -100,6 +101,20 @@ def download_exchange_symbols(exchange_name, environ=None):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def symbols_parser(asset_def):
|
||||||
|
for key, value in asset_def.items():
|
||||||
|
match = isinstance(value, string_types) \
|
||||||
|
and re.search(r'(\d{4}-\d{2}-\d{2})', value)
|
||||||
|
|
||||||
|
if match:
|
||||||
|
try:
|
||||||
|
asset_def[key] = pd.to_datetime(value, utc=True)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return asset_def
|
||||||
|
|
||||||
|
|
||||||
def get_exchange_symbols(exchange_name, is_local=False, environ=None):
|
def get_exchange_symbols(exchange_name, is_local=False, environ=None):
|
||||||
"""
|
"""
|
||||||
The de-serialized content of the exchange's symbols.json.
|
The de-serialized content of the exchange's symbols.json.
|
||||||
@@ -125,10 +140,10 @@ def get_exchange_symbols(exchange_name, is_local=False, environ=None):
|
|||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
with open(filename) as data_file:
|
with open(filename) as data_file:
|
||||||
try:
|
try:
|
||||||
data = json.load(data_file)
|
data = json.load(data_file, object_hook=symbols_parser)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
except ValueError:
|
except ValueError as e:
|
||||||
return dict()
|
return dict()
|
||||||
else:
|
else:
|
||||||
raise ExchangeSymbolsNotFound(
|
raise ExchangeSymbolsNotFound(
|
||||||
@@ -571,3 +586,44 @@ def resample_history_df(df, freq, field):
|
|||||||
|
|
||||||
resampled_df = df.resample(freq).agg(agg)
|
resampled_df = df.resample(freq).agg(agg)
|
||||||
return resampled_df
|
return resampled_df
|
||||||
|
|
||||||
|
|
||||||
|
def mixin_market_params(exchange_name, params, market):
|
||||||
|
"""
|
||||||
|
Applies a CCXT market dict to parameters of TradingPair init.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
params: dict[Object]
|
||||||
|
market: dict[Object]
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
|
||||||
|
"""
|
||||||
|
# TODO: make this more externalized / configurable
|
||||||
|
if 'lot' in market:
|
||||||
|
params['min_trade_size'] = market['lot']
|
||||||
|
|
||||||
|
if exchange_name == 'bitfinex':
|
||||||
|
params['maker'] = 0.001
|
||||||
|
params['taker'] = 0.002
|
||||||
|
|
||||||
|
elif 'maker' in market and 'taker' in market \
|
||||||
|
and market['maker'] is not None and market['taker'] is not None:
|
||||||
|
params['maker'] = market['maker']
|
||||||
|
params['taker'] = market['taker']
|
||||||
|
|
||||||
|
else:
|
||||||
|
# TODO: default commission, make configurable
|
||||||
|
params['maker'] = 0.0015
|
||||||
|
params['taker'] = 0.0025
|
||||||
|
|
||||||
|
info = market['info'] if 'info' in market else None
|
||||||
|
if info:
|
||||||
|
if 'minimum_order_size' in info:
|
||||||
|
params['min_trade_size'] = float(info['minimum_order_size'])
|
||||||
|
|
||||||
|
|
||||||
|
def from_ms_timestamp(ms):
|
||||||
|
return pd.to_datetime(ms, unit='ms', utc=True)
|
||||||
|
|||||||
@@ -1,39 +1,32 @@
|
|||||||
from catalyst.exchange.bitfinex.bitfinex import Bitfinex
|
import os
|
||||||
from catalyst.exchange.bittrex.bittrex import Bittrex
|
|
||||||
from catalyst.exchange.exchange_errors import ExchangeNotFoundError
|
from catalyst.exchange.ccxt.ccxt_exchange import CCXT
|
||||||
from catalyst.exchange.exchange_utils import get_exchange_auth
|
from catalyst.exchange.exchange_errors import ExchangeAuthEmpty
|
||||||
from catalyst.exchange.poloniex.poloniex import Poloniex
|
from catalyst.exchange.exchange_utils import get_exchange_auth, \
|
||||||
|
get_exchange_folder
|
||||||
|
|
||||||
|
|
||||||
def get_exchange(exchange_name, base_currency=None):
|
def get_exchange(exchange_name, base_currency=None, portfolio=None,
|
||||||
|
must_authenticate=False):
|
||||||
exchange_auth = get_exchange_auth(exchange_name)
|
exchange_auth = get_exchange_auth(exchange_name)
|
||||||
if exchange_name == 'bitfinex':
|
|
||||||
return Bitfinex(
|
has_auth = (exchange_auth['key'] != '' and exchange_auth['secret'] != '')
|
||||||
|
if must_authenticate and not has_auth:
|
||||||
|
raise ExchangeAuthEmpty(
|
||||||
|
exchange=exchange_name.title(),
|
||||||
|
filename=os.path.join(
|
||||||
|
get_exchange_folder(exchange_name), 'auth.json'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return CCXT(
|
||||||
|
exchange_name=exchange_name,
|
||||||
key=exchange_auth['key'],
|
key=exchange_auth['key'],
|
||||||
secret=exchange_auth['secret'],
|
secret=exchange_auth['secret'],
|
||||||
base_currency=base_currency,
|
base_currency=base_currency,
|
||||||
portfolio=None
|
portfolio=portfolio
|
||||||
)
|
)
|
||||||
|
|
||||||
elif exchange_name == 'bittrex':
|
|
||||||
return Bittrex(
|
|
||||||
key=exchange_auth['key'],
|
|
||||||
secret=exchange_auth['secret'],
|
|
||||||
base_currency=base_currency,
|
|
||||||
portfolio=None
|
|
||||||
)
|
|
||||||
|
|
||||||
elif exchange_name == 'poloniex':
|
|
||||||
return Poloniex(
|
|
||||||
key=exchange_auth['key'],
|
|
||||||
secret=exchange_auth['secret'],
|
|
||||||
base_currency=base_currency,
|
|
||||||
portfolio=None
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise ExchangeNotFoundError(exchange_name=exchange_name)
|
|
||||||
|
|
||||||
|
|
||||||
def get_exchanges(exchange_names):
|
def get_exchanges(exchange_names):
|
||||||
exchanges = dict()
|
exchanges = dict()
|
||||||
|
|||||||
@@ -153,11 +153,11 @@ def get_pretty_stats(stats_df, recorded_cols=None, num_rows=10):
|
|||||||
def format_positions(positions):
|
def format_positions(positions):
|
||||||
parts = []
|
parts = []
|
||||||
for position in positions:
|
for position in positions:
|
||||||
msg = '{amount:.2f}{market} cost basis {cost_basis:.4f}{base}'.format(
|
msg = '{amount:.2f}{base} cost basis {cost_basis:.4f}{quote}'.format(
|
||||||
amount=position['amount'],
|
amount=position['amount'],
|
||||||
market=position['sid'].market_currency,
|
base=position['sid'].base_currency,
|
||||||
cost_basis=position['cost_basis'],
|
cost_basis=position['cost_basis'],
|
||||||
base=position['sid'].base_currency
|
quote=position['sid'].quote_currency
|
||||||
)
|
)
|
||||||
parts.append(msg)
|
parts.append(msg)
|
||||||
return ', '.join(parts)
|
return ', '.join(parts)
|
||||||
|
|||||||
@@ -55,4 +55,4 @@ from .core import ( # noqa
|
|||||||
write_bcolz_minute_data,
|
write_bcolz_minute_data,
|
||||||
write_compressed,
|
write_compressed,
|
||||||
)
|
)
|
||||||
from .fixtures import ZiplineTestCase # noqa
|
from .fixtures import CatalystTestCase # noqa
|
||||||
|
|||||||
@@ -643,7 +643,7 @@ def create_data_portal_from_trade_history(asset_finder, trading_calendar,
|
|||||||
return DataPortal(
|
return DataPortal(
|
||||||
asset_finder, trading_calendar,
|
asset_finder, trading_calendar,
|
||||||
first_trading_day=equity_daily_reader.first_trading_day,
|
first_trading_day=equity_daily_reader.first_trading_day,
|
||||||
equity_daily_reader=equity_daily_reader,
|
daily_reader=equity_daily_reader,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
minutes = trading_calendar.minutes_in_range(
|
minutes = trading_calendar.minutes_in_range(
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ from catalyst.utils.paths import ensure_directory
|
|||||||
catalyst_dir = os.path.dirname(catalyst.__file__)
|
catalyst_dir = os.path.dirname(catalyst.__file__)
|
||||||
|
|
||||||
|
|
||||||
class ZiplineTestCase(with_metaclass(FinalMeta, TestCase)):
|
class CatalystTestCase(with_metaclass(FinalMeta, TestCase)):
|
||||||
"""
|
"""
|
||||||
Shared extensions to core unittest.TestCase.
|
Shared extensions to core unittest.TestCase.
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ class ZiplineTestCase(with_metaclass(FinalMeta, TestCase)):
|
|||||||
cls._base_init_fixtures_was_called = False
|
cls._base_init_fixtures_was_called = False
|
||||||
cls.init_class_fixtures()
|
cls.init_class_fixtures()
|
||||||
assert cls._base_init_fixtures_was_called, (
|
assert cls._base_init_fixtures_was_called, (
|
||||||
"ZiplineTestCase.init_class_fixtures() was not called.\n"
|
"CatalystTestCase.init_class_fixtures() was not called.\n"
|
||||||
"This probably means that you overrode init_class_fixtures"
|
"This probably means that you overrode init_class_fixtures"
|
||||||
" without calling super()."
|
" without calling super()."
|
||||||
)
|
)
|
||||||
@@ -170,7 +170,7 @@ class ZiplineTestCase(with_metaclass(FinalMeta, TestCase)):
|
|||||||
self._init_instance_fixtures_was_called = False
|
self._init_instance_fixtures_was_called = False
|
||||||
self.init_instance_fixtures()
|
self.init_instance_fixtures()
|
||||||
assert self._init_instance_fixtures_was_called, (
|
assert self._init_instance_fixtures_was_called, (
|
||||||
"ZiplineTestCase.init_instance_fixtures() was not"
|
"CatalystTestCase.init_instance_fixtures() was not"
|
||||||
" called.\n"
|
" called.\n"
|
||||||
"This probably means that you overrode"
|
"This probably means that you overrode"
|
||||||
" init_instance_fixtures without calling super()."
|
" init_instance_fixtures without calling super()."
|
||||||
@@ -251,7 +251,7 @@ def alias(attr_name):
|
|||||||
|
|
||||||
class WithDefaultDateBounds(object):
|
class WithDefaultDateBounds(object):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin which makes it possible to synchronize date bounds
|
CatalystTestCase mixin which makes it possible to synchronize date bounds
|
||||||
across fixtures.
|
across fixtures.
|
||||||
|
|
||||||
This fixture should always be the last fixture in bases of any fixture or
|
This fixture should always be the last fixture in bases of any fixture or
|
||||||
@@ -264,13 +264,13 @@ class WithDefaultDateBounds(object):
|
|||||||
The date bounds to be used for fixtures that want to have consistent
|
The date bounds to be used for fixtures that want to have consistent
|
||||||
dates.
|
dates.
|
||||||
"""
|
"""
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2016-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-12-29', tz='utc')
|
END_DATE = pd.Timestamp('2016-12-29', tz='utc')
|
||||||
|
|
||||||
|
|
||||||
class WithLogger(object):
|
class WithLogger(object):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.log_handler as an instance-level
|
CatalystTestCase mixin providing cls.log_handler as an instance-level
|
||||||
fixture.
|
fixture.
|
||||||
|
|
||||||
After init_instance_fixtures has been called `self.log_handler` will be a
|
After init_instance_fixtures has been called `self.log_handler` will be a
|
||||||
@@ -295,7 +295,7 @@ class WithLogger(object):
|
|||||||
|
|
||||||
class WithAssetFinder(WithDefaultDateBounds):
|
class WithAssetFinder(WithDefaultDateBounds):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.asset_finder as a class-level fixture.
|
CatalystTestCase mixin providing cls.asset_finder as a class-level fixture.
|
||||||
|
|
||||||
After init_class_fixtures has been called, `cls.asset_finder` is populated
|
After init_class_fixtures has been called, `cls.asset_finder` is populated
|
||||||
with an AssetFinder.
|
with an AssetFinder.
|
||||||
@@ -402,7 +402,7 @@ class WithAssetFinder(WithDefaultDateBounds):
|
|||||||
|
|
||||||
class WithTradingCalendars(object):
|
class WithTradingCalendars(object):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.trading_calendar,
|
CatalystTestCase mixin providing cls.trading_calendar,
|
||||||
cls.all_trading_calendars, cls.trading_calendar_for_asset_type as a
|
cls.all_trading_calendars, cls.trading_calendar_for_asset_type as a
|
||||||
class-level fixture.
|
class-level fixture.
|
||||||
|
|
||||||
@@ -423,7 +423,7 @@ class WithTradingCalendars(object):
|
|||||||
with that asset type.
|
with that asset type.
|
||||||
"""
|
"""
|
||||||
TRADING_CALENDAR_STRS = ('NYSE',)
|
TRADING_CALENDAR_STRS = ('NYSE',)
|
||||||
TRADING_CALENDAR_FOR_ASSET_TYPE = {Equity: 'NYSE', Future: 'us_futures'}
|
TRADING_CALENDAR_FOR_ASSET_TYPE = {Equity: 'NYSE', Future: 'us_futures', }
|
||||||
TRADING_CALENDAR_FOR_EXCHANGE = {}
|
TRADING_CALENDAR_FOR_EXCHANGE = {}
|
||||||
# For backwards compatibility, exisitng tests and fixtures refer to
|
# For backwards compatibility, exisitng tests and fixtures refer to
|
||||||
# `trading_calendar` with the assumption that the value is the NYSE
|
# `trading_calendar` with the assumption that the value is the NYSE
|
||||||
@@ -460,7 +460,7 @@ class WithTradingEnvironment(WithAssetFinder,
|
|||||||
WithTradingCalendars,
|
WithTradingCalendars,
|
||||||
WithDefaultDateBounds):
|
WithDefaultDateBounds):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.env as a class-level fixture.
|
CatalystTestCase mixin providing cls.env as a class-level fixture.
|
||||||
|
|
||||||
After ``init_class_fixtures`` has been called, `cls.env` is populated
|
After ``init_class_fixtures`` has been called, `cls.env` is populated
|
||||||
with a trading environment whose `asset_finder` is the result of
|
with a trading environment whose `asset_finder` is the result of
|
||||||
@@ -560,7 +560,7 @@ class WithTradingEnvironment(WithAssetFinder,
|
|||||||
|
|
||||||
class WithSimParams(WithTradingEnvironment):
|
class WithSimParams(WithTradingEnvironment):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.sim_params as a class level fixture.
|
CatalystTestCase mixin providing cls.sim_params as a class level fixture.
|
||||||
|
|
||||||
The arguments used to construct the trading environment may be overridded
|
The arguments used to construct the trading environment may be overridded
|
||||||
by putting ``SIM_PARAMS_{argname}`` in the class dict except for the
|
by putting ``SIM_PARAMS_{argname}`` in the class dict except for the
|
||||||
@@ -615,7 +615,7 @@ class WithSimParams(WithTradingEnvironment):
|
|||||||
|
|
||||||
class WithTradingSessions(WithTradingCalendars, WithDefaultDateBounds):
|
class WithTradingSessions(WithTradingCalendars, WithDefaultDateBounds):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.trading_days, cls.all_trading_sessions
|
CatalystTestCase mixin providing cls.trading_days, cls.all_trading_sessions
|
||||||
as a class-level fixture.
|
as a class-level fixture.
|
||||||
|
|
||||||
After init_class_fixtures has been called, `cls.all_trading_sessions`
|
After init_class_fixtures has been called, `cls.all_trading_sessions`
|
||||||
@@ -668,7 +668,7 @@ class WithTradingSessions(WithTradingCalendars, WithDefaultDateBounds):
|
|||||||
|
|
||||||
class WithTmpDir(object):
|
class WithTmpDir(object):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixing providing cls.tmpdir as a class-level fixture.
|
CatalystTestCase mixing providing cls.tmpdir as a class-level fixture.
|
||||||
|
|
||||||
After init_class_fixtures has been called, `cls.tmpdir` is populated with
|
After init_class_fixtures has been called, `cls.tmpdir` is populated with
|
||||||
a `testfixtures.TempDirectory` object whose path is `cls.TMP_DIR_PATH`.
|
a `testfixtures.TempDirectory` object whose path is `cls.TMP_DIR_PATH`.
|
||||||
@@ -691,7 +691,7 @@ class WithTmpDir(object):
|
|||||||
|
|
||||||
class WithInstanceTmpDir(object):
|
class WithInstanceTmpDir(object):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixing providing self.tmpdir as an instance-level fixture.
|
CatalystTestCase mixing providing self.tmpdir as an instance-level fixture.
|
||||||
|
|
||||||
After init_instance_fixtures has been called, `self.tmpdir` is populated
|
After init_instance_fixtures has been called, `self.tmpdir` is populated
|
||||||
with a `testfixtures.TempDirectory` object whose path is
|
with a `testfixtures.TempDirectory` object whose path is
|
||||||
@@ -714,7 +714,7 @@ class WithInstanceTmpDir(object):
|
|||||||
|
|
||||||
class WithEquityDailyBarData(WithTradingEnvironment):
|
class WithEquityDailyBarData(WithTradingEnvironment):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.make_equity_daily_bar_data.
|
CatalystTestCase mixin providing cls.make_equity_daily_bar_data.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
@@ -810,7 +810,7 @@ class WithEquityDailyBarData(WithTradingEnvironment):
|
|||||||
|
|
||||||
class WithBcolzEquityDailyBarReader(WithEquityDailyBarData, WithTmpDir):
|
class WithBcolzEquityDailyBarReader(WithEquityDailyBarData, WithTmpDir):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.bcolz_daily_bar_path,
|
CatalystTestCase mixin providing cls.bcolz_daily_bar_path,
|
||||||
cls.bcolz_daily_bar_ctable, and cls.bcolz_equity_daily_bar_reader
|
cls.bcolz_daily_bar_ctable, and cls.bcolz_equity_daily_bar_reader
|
||||||
class level fixtures.
|
class level fixtures.
|
||||||
|
|
||||||
@@ -895,7 +895,7 @@ class WithBcolzEquityDailyBarReader(WithEquityDailyBarData, WithTmpDir):
|
|||||||
|
|
||||||
class WithBcolzEquityDailyBarReaderFromCSVs(WithBcolzEquityDailyBarReader):
|
class WithBcolzEquityDailyBarReaderFromCSVs(WithBcolzEquityDailyBarReader):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin that provides
|
CatalystTestCase mixin that provides
|
||||||
cls.bcolz_equity_daily_bar_reader from a mapping of sids to CSV
|
cls.bcolz_equity_daily_bar_reader from a mapping of sids to CSV
|
||||||
file paths.
|
file paths.
|
||||||
"""
|
"""
|
||||||
@@ -925,7 +925,7 @@ class _WithMinuteBarDataBase(WithTradingEnvironment):
|
|||||||
|
|
||||||
class WithEquityMinuteBarData(_WithMinuteBarDataBase):
|
class WithEquityMinuteBarData(_WithMinuteBarDataBase):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.equity_minute_bar_days.
|
CatalystTestCase mixin providing cls.equity_minute_bar_days.
|
||||||
|
|
||||||
After init_class_fixtures has been called:
|
After init_class_fixtures has been called:
|
||||||
- `cls.equity_minute_bar_days` has the range over which data has been
|
- `cls.equity_minute_bar_days` has the range over which data has been
|
||||||
@@ -984,7 +984,7 @@ class WithEquityMinuteBarData(_WithMinuteBarDataBase):
|
|||||||
|
|
||||||
class WithFutureMinuteBarData(_WithMinuteBarDataBase):
|
class WithFutureMinuteBarData(_WithMinuteBarDataBase):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.future_minute_bar_days.
|
CatalystTestCase mixin providing cls.future_minute_bar_days.
|
||||||
|
|
||||||
After init_class_fixtures has been called:
|
After init_class_fixtures has been called:
|
||||||
- `cls.future_minute_bar_days` has the range over which data has been
|
- `cls.future_minute_bar_days` has the range over which data has been
|
||||||
@@ -1044,7 +1044,7 @@ class WithFutureMinuteBarData(_WithMinuteBarDataBase):
|
|||||||
|
|
||||||
class WithBcolzEquityMinuteBarReader(WithEquityMinuteBarData, WithTmpDir):
|
class WithBcolzEquityMinuteBarReader(WithEquityMinuteBarData, WithTmpDir):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.bcolz_minute_bar_path,
|
CatalystTestCase mixin providing cls.bcolz_minute_bar_path,
|
||||||
cls.bcolz_minute_bar_ctable, and cls.bcolz_equity_minute_bar_reader
|
cls.bcolz_minute_bar_ctable, and cls.bcolz_equity_minute_bar_reader
|
||||||
class level fixtures.
|
class level fixtures.
|
||||||
|
|
||||||
@@ -1103,7 +1103,7 @@ class WithBcolzEquityMinuteBarReader(WithEquityMinuteBarData, WithTmpDir):
|
|||||||
|
|
||||||
class WithBcolzFutureMinuteBarReader(WithFutureMinuteBarData, WithTmpDir):
|
class WithBcolzFutureMinuteBarReader(WithFutureMinuteBarData, WithTmpDir):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.bcolz_minute_bar_path,
|
CatalystTestCase mixin providing cls.bcolz_minute_bar_path,
|
||||||
cls.bcolz_minute_bar_ctable, and cls.bcolz_equity_minute_bar_reader
|
cls.bcolz_minute_bar_ctable, and cls.bcolz_equity_minute_bar_reader
|
||||||
class level fixtures.
|
class level fixtures.
|
||||||
|
|
||||||
@@ -1227,7 +1227,7 @@ class WithConstantFutureMinuteBarData(WithFutureMinuteBarData):
|
|||||||
|
|
||||||
class WithAdjustmentReader(WithBcolzEquityDailyBarReader):
|
class WithAdjustmentReader(WithBcolzEquityDailyBarReader):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.adjustment_reader as a class level
|
CatalystTestCase mixin providing cls.adjustment_reader as a class level
|
||||||
fixture.
|
fixture.
|
||||||
|
|
||||||
After init_class_fixtures has been called, `cls.adjustment_reader` will be
|
After init_class_fixtures has been called, `cls.adjustment_reader` will be
|
||||||
@@ -1359,7 +1359,7 @@ class WithEquityPricingPipelineEngine(WithAdjustmentReader,
|
|||||||
|
|
||||||
class WithSeededRandomPipelineEngine(WithTradingSessions, WithAssetFinder):
|
class WithSeededRandomPipelineEngine(WithTradingSessions, WithAssetFinder):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing class-level fixtures for running pipelines
|
CatalystTestCase mixin providing class-level fixtures for running pipelines
|
||||||
against deterministically-generated random data.
|
against deterministically-generated random data.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
@@ -1434,7 +1434,7 @@ class WithDataPortal(WithAdjustmentReader,
|
|||||||
WithBcolzEquityMinuteBarReader,
|
WithBcolzEquityMinuteBarReader,
|
||||||
WithBcolzFutureMinuteBarReader):
|
WithBcolzFutureMinuteBarReader):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing self.data_portal as an instance level
|
CatalystTestCase mixin providing self.data_portal as an instance level
|
||||||
fixture.
|
fixture.
|
||||||
|
|
||||||
After init_instance_fixtures has been called, `self.data_portal` will be
|
After init_instance_fixtures has been called, `self.data_portal` will be
|
||||||
@@ -1485,12 +1485,12 @@ class WithDataPortal(WithAdjustmentReader,
|
|||||||
self.env.asset_finder,
|
self.env.asset_finder,
|
||||||
self.trading_calendar,
|
self.trading_calendar,
|
||||||
first_trading_day=self.DATA_PORTAL_FIRST_TRADING_DAY,
|
first_trading_day=self.DATA_PORTAL_FIRST_TRADING_DAY,
|
||||||
equity_daily_reader=(
|
daily_reader=(
|
||||||
self.bcolz_equity_daily_bar_reader
|
self.bcolz_equity_daily_bar_reader
|
||||||
if self.DATA_PORTAL_USE_DAILY_DATA else
|
if self.DATA_PORTAL_USE_DAILY_DATA else
|
||||||
None
|
None
|
||||||
),
|
),
|
||||||
equity_minute_reader=(
|
minute_reader=(
|
||||||
self.bcolz_equity_minute_bar_reader
|
self.bcolz_equity_minute_bar_reader
|
||||||
if self.DATA_PORTAL_USE_MINUTE_DATA else
|
if self.DATA_PORTAL_USE_MINUTE_DATA else
|
||||||
None
|
None
|
||||||
@@ -1526,7 +1526,7 @@ class WithDataPortal(WithAdjustmentReader,
|
|||||||
|
|
||||||
class WithResponses(object):
|
class WithResponses(object):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin that provides self.responses as an instance
|
CatalystTestCase mixin that provides self.responses as an instance
|
||||||
fixture.
|
fixture.
|
||||||
|
|
||||||
After init_instance_fixtures has been called, `self.responses` will be
|
After init_instance_fixtures has been called, `self.responses` will be
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ from catalyst.utils.input_validation import expect_types
|
|||||||
__all__ = ['load_from_yahoo', 'load_bars_from_yahoo']
|
__all__ = ['load_from_yahoo', 'load_bars_from_yahoo']
|
||||||
|
|
||||||
|
|
||||||
def create_simulation_parameters(year=2006, start=None, end=None,
|
def create_simulation_parameters(year=2016, start=None, end=None,
|
||||||
capital_base=float("1.0e5"),
|
capital_base=float("1.0e5"),
|
||||||
num_days=None,
|
num_days=None,
|
||||||
data_frequency='daily',
|
data_frequency='daily',
|
||||||
|
|||||||
+17
-44
@@ -11,9 +11,7 @@ import pandas as pd
|
|||||||
|
|
||||||
from catalyst.data.bundles import load
|
from catalyst.data.bundles import load
|
||||||
from catalyst.data.data_portal import DataPortal
|
from catalyst.data.data_portal import DataPortal
|
||||||
from catalyst.exchange.bittrex.bittrex import Bittrex
|
from catalyst.exchange.factory import get_exchange
|
||||||
from catalyst.exchange.bitfinex.bitfinex import Bitfinex
|
|
||||||
from catalyst.exchange.poloniex.poloniex import Poloniex
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from pygments import highlight
|
from pygments import highlight
|
||||||
@@ -39,11 +37,9 @@ from catalyst.exchange.exchange_data_portal import DataPortalExchangeLive, \
|
|||||||
from catalyst.exchange.asset_finder_exchange import AssetFinderExchange
|
from catalyst.exchange.asset_finder_exchange import AssetFinderExchange
|
||||||
from catalyst.exchange.exchange_portfolio import ExchangePortfolio
|
from catalyst.exchange.exchange_portfolio import ExchangePortfolio
|
||||||
from catalyst.exchange.exchange_errors import (
|
from catalyst.exchange.exchange_errors import (
|
||||||
ExchangeRequestError, ExchangeAuthEmpty,
|
ExchangeRequestError, ExchangeRequestErrorTooManyAttempts,
|
||||||
ExchangeRequestErrorTooManyAttempts,
|
BaseCurrencyNotFoundError)
|
||||||
BaseCurrencyNotFoundError, ExchangeNotFoundError)
|
from catalyst.exchange.exchange_utils import get_algo_object
|
||||||
from catalyst.exchange.exchange_utils import get_exchange_auth, \
|
|
||||||
get_algo_object, get_exchange_folder
|
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
|
|
||||||
from catalyst.constants import LOG_LEVEL
|
from catalyst.constants import LOG_LEVEL
|
||||||
@@ -94,7 +90,8 @@ def _run(handle_data,
|
|||||||
exchange,
|
exchange,
|
||||||
algo_namespace,
|
algo_namespace,
|
||||||
base_currency,
|
base_currency,
|
||||||
live_graph):
|
live_graph,
|
||||||
|
simulate_orders):
|
||||||
"""Run a backtest for the given algorithm.
|
"""Run a backtest for the given algorithm.
|
||||||
|
|
||||||
This is shared between the cli and :func:`catalyst.run_algo`.
|
This is shared between the cli and :func:`catalyst.run_algo`.
|
||||||
@@ -164,42 +161,15 @@ def _run(handle_data,
|
|||||||
|
|
||||||
if portfolio is None:
|
if portfolio is None:
|
||||||
portfolio = ExchangePortfolio(
|
portfolio = ExchangePortfolio(
|
||||||
start_date=pd.Timestamp.utcnow()
|
start if start is not None else pd.Timestamp.utcnow()
|
||||||
)
|
)
|
||||||
|
|
||||||
# This corresponds to the json file containing api token info
|
exchanges[exchange_name] = get_exchange(
|
||||||
exchange_auth = get_exchange_auth(exchange_name)
|
exchange_name=exchange_name,
|
||||||
|
|
||||||
if live and (exchange_auth['key'] == '' \
|
|
||||||
or exchange_auth['secret'] == ''):
|
|
||||||
raise ExchangeAuthEmpty(
|
|
||||||
exchange=exchange_name.title(),
|
|
||||||
filename=os.path.join(
|
|
||||||
get_exchange_folder(exchange_name, environ), 'auth.json'))
|
|
||||||
|
|
||||||
if exchange_name == 'bitfinex':
|
|
||||||
exchanges[exchange_name] = Bitfinex(
|
|
||||||
key=exchange_auth['key'],
|
|
||||||
secret=exchange_auth['secret'],
|
|
||||||
base_currency=base_currency,
|
base_currency=base_currency,
|
||||||
portfolio=portfolio
|
portfolio=portfolio,
|
||||||
|
must_authenticate=live,
|
||||||
)
|
)
|
||||||
elif exchange_name == 'bittrex':
|
|
||||||
exchanges[exchange_name] = Bittrex(
|
|
||||||
key=exchange_auth['key'],
|
|
||||||
secret=exchange_auth['secret'],
|
|
||||||
base_currency=base_currency,
|
|
||||||
portfolio=portfolio
|
|
||||||
)
|
|
||||||
elif exchange_name == 'poloniex':
|
|
||||||
exchanges[exchange_name] = Poloniex(
|
|
||||||
key=exchange_auth['key'],
|
|
||||||
secret=exchange_auth['secret'],
|
|
||||||
base_currency=base_currency,
|
|
||||||
portfolio=portfolio
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise ExchangeNotFoundError(exchange_name=exchange_name)
|
|
||||||
|
|
||||||
open_calendar = get_calendar('OPEN')
|
open_calendar = get_calendar('OPEN')
|
||||||
|
|
||||||
@@ -263,7 +233,7 @@ def _run(handle_data,
|
|||||||
)
|
)
|
||||||
|
|
||||||
if base_currency in balances:
|
if base_currency in balances:
|
||||||
base_currency_available = balances[base_currency]
|
base_currency_available = balances[base_currency]['free']
|
||||||
log.info(
|
log.info(
|
||||||
'base currency available in the account: {} {}'.format(
|
'base currency available in the account: {} {}'.format(
|
||||||
base_currency_available, base_currency
|
base_currency_available, base_currency
|
||||||
@@ -308,7 +278,8 @@ def _run(handle_data,
|
|||||||
ExchangeTradingAlgorithmLive,
|
ExchangeTradingAlgorithmLive,
|
||||||
exchanges=exchanges,
|
exchanges=exchanges,
|
||||||
algo_namespace=algo_namespace,
|
algo_namespace=algo_namespace,
|
||||||
live_graph=live_graph
|
live_graph=live_graph,
|
||||||
|
simulate_orders=simulate_orders
|
||||||
)
|
)
|
||||||
elif exchanges:
|
elif exchanges:
|
||||||
# Removed the existing Poloniex fork to keep things simple
|
# Removed the existing Poloniex fork to keep things simple
|
||||||
@@ -470,6 +441,7 @@ def run_algorithm(initialize,
|
|||||||
base_currency=None,
|
base_currency=None,
|
||||||
algo_namespace=None,
|
algo_namespace=None,
|
||||||
live_graph=False,
|
live_graph=False,
|
||||||
|
simulate_orders=True,
|
||||||
output=os.devnull):
|
output=os.devnull):
|
||||||
"""Run a trading algorithm.
|
"""Run a trading algorithm.
|
||||||
|
|
||||||
@@ -591,5 +563,6 @@ def run_algorithm(initialize,
|
|||||||
exchange=exchange_name,
|
exchange=exchange_name,
|
||||||
algo_namespace=algo_namespace,
|
algo_namespace=algo_namespace,
|
||||||
base_currency=base_currency,
|
base_currency=base_currency,
|
||||||
live_graph=live_graph
|
live_graph=live_graph,
|
||||||
|
simulate_orders=simulate_orders
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -546,6 +546,7 @@ only bought bitcoin every chance it got.
|
|||||||
sudo apt install python-tk
|
sudo apt install python-tk
|
||||||
|
|
||||||
|
|
||||||
|
.. _history:
|
||||||
|
|
||||||
Access to previous prices using ``history``
|
Access to previous prices using ``history``
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
+509
-52
@@ -2,28 +2,109 @@
|
|||||||
Example Algorithms
|
Example Algorithms
|
||||||
==================
|
==================
|
||||||
|
|
||||||
This section documents a small number of example algorithms to complement the
|
This section documents a number of example algorithms to complement the
|
||||||
beginner tutorial, and show how other trading algorithms can be implemented
|
beginner tutorial, and show how other trading algorithms can be implemented
|
||||||
using Catalyst:
|
using Catalyst.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
- :ref:`Buy BTC Simple<buy_btc_simple>`: The simplest algorithm that introduces
|
||||||
|
the ``initialize()`` and ``handle_data()`` functions, and is used in the
|
||||||
|
:doc:`beginner tutorial<beginner-tutorial>` to show how to run catalyst
|
||||||
|
for the first time.
|
||||||
|
|
||||||
|
- :ref:`Buy and Hodl <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``.
|
||||||
|
|
||||||
|
- :ref:`Dual Moving Average Crossover<dual_moving_average>`: A classic momentum
|
||||||
|
strategy used in the second part of the
|
||||||
|
`beginner tutorial <beginner-tutorial.html#history>`_ 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.
|
||||||
|
|
||||||
|
- :ref:`Mean Reversion Algorithm <mean_reversion>`: Another simple momentum
|
||||||
|
strategy that is used in our
|
||||||
|
`two-part video tutorial <videos.html#backtesting-a-strategy>`_ to show how
|
||||||
|
to get started in backtesting and live trading with Catalyst.
|
||||||
|
|
||||||
|
- :ref:`Portfolio Optimization <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 <https://blog.enigma.co/markowitz-portfolio-optimization-for-cryptocurrencies-in-catalyst-b23c38652556>`_.
|
||||||
|
|
||||||
|
|
||||||
|
.. _buy_btc_simple:
|
||||||
|
|
||||||
|
Buy BTC Simple Algorithm
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Source code: `examples/buy_btc_simple.py <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/buy_btc_simple.py>`_
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
'''
|
||||||
|
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 --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
|
||||||
|
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 --end 2017-9-30 -o buy_btc_simple_out.pickle
|
||||||
|
|
||||||
|
To see which assets are available on each exchange, visit:
|
||||||
|
https://www.enigma.co/catalyst/status
|
||||||
|
'''
|
||||||
|
|
||||||
|
from catalyst.api import order, record, symbol
|
||||||
|
|
||||||
|
def initialize(context):
|
||||||
|
context.asset = symbol('btc_usd')
|
||||||
|
|
||||||
|
def handle_data(context, data):
|
||||||
|
order(context.asset, 1)
|
||||||
|
record(btc = data.current(context.asset, 'price'))
|
||||||
|
|
||||||
|
This simple algorithm does not produce any output nor displays any chart.
|
||||||
|
|
||||||
|
|
||||||
.. _buy_and_hodl:
|
.. _buy_and_hodl:
|
||||||
|
|
||||||
Buy and Hodl Algorithm
|
Buy and Hodl Algorithm
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
source: `examples/buy_and_hodl.py <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/buy_and_hodl.py>`_
|
Source code: `examples/buy_and_hodl.py <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/buy_and_hodl.py>`_
|
||||||
|
|
||||||
First ingest the historical pricing data needed to run this algorithm:
|
First ingest the historical pricing data needed to run this algorithm:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
catalyst ingest-exchange -x poloniex -f daily -i btc_usdt
|
catalyst ingest-exchange -x bitfinex -f daily -i btc_usd
|
||||||
|
|
||||||
Then, you can run the code below with the following command:
|
Then, you can run the code below with the following command:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. 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
|
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:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python buy_and_hodl.py
|
||||||
|
|
||||||
|
|
||||||
This command will run the trading algorithm in the specified time range and
|
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
|
plot the resulting performance using the matplotlib library. You can choose any
|
||||||
@@ -52,18 +133,15 @@ one day prior to the current date.
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
from catalyst.api import (
|
from catalyst import run_algorithm
|
||||||
order_target_value,
|
from catalyst.api import (order_target_value, symbol, record,
|
||||||
symbol,
|
cancel_order, get_open_orders, )
|
||||||
record,
|
|
||||||
cancel_order,
|
|
||||||
get_open_orders,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -95,6 +173,7 @@ one day prior to the current date.
|
|||||||
|
|
||||||
# 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,
|
||||||
@@ -113,7 +192,6 @@ one day prior to the current date.
|
|||||||
|
|
||||||
|
|
||||||
def analyze(context=None, results=None):
|
def analyze(context=None, results=None):
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
# Plot the portfolio and asset data.
|
# Plot the portfolio and asset data.
|
||||||
ax1 = plt.subplot(611)
|
ax1 = plt.subplot(611)
|
||||||
@@ -128,12 +206,13 @@ one day prior to the current date.
|
|||||||
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)
|
||||||
@@ -172,19 +251,205 @@ one day prior to the current date.
|
|||||||
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='daily',
|
||||||
|
initialize=initialize,
|
||||||
|
handle_data=handle_data,
|
||||||
|
analyze=analyze,
|
||||||
|
exchange_name='bitfinex',
|
||||||
|
algo_namespace='buy_and_hodl',
|
||||||
|
base_currency='usd',
|
||||||
|
start=pd.to_datetime('2015-03-01', utc=True),
|
||||||
|
end=pd.to_datetime('2017-10-31', utc=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
.. image:: https://s3.amazonaws.com/enigmaco-docs/github.io/example_buy_and_hodl.png
|
||||||
|
|
||||||
|
.. _dual_moving_average:
|
||||||
|
|
||||||
|
Dual Moving Average Crossover
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Source Code: `examples/dual_moving_average.py <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/dual_moving_average.py>`_
|
||||||
|
|
||||||
|
This strategy is covered in detail in the last part of
|
||||||
|
`this tutorial <beginner-tutorial.html#history>`_.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
|
||||||
|
.. image:: https://s3.amazonaws.com/enigmaco-docs/github.io/tutorial_dual_moving_average.png
|
||||||
|
|
||||||
|
|
||||||
.. _mean_reversion:
|
.. _mean_reversion:
|
||||||
|
|
||||||
Mean Reversion Algorithm
|
Mean Reversion Algorithm
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
source: `examples/mean_reversion_simple.py <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/mean_reversion_simple.py>`_
|
Source code: `examples/mean_reversion_simple.py <https://github.com/enigmampc/catalyst/blob/master/catalyst/examples/mean_reversion_simple.py>`_
|
||||||
|
|
||||||
This algorithm is based on a simple momentum strategy. When the cryptoasset goes
|
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.
|
up quickly, we're going to buy; when it goes down quickly, we're going to sell.
|
||||||
Hopefully, we'll ride the waves.
|
Hopefully, we'll ride the waves.
|
||||||
|
|
||||||
We are choosing to run this trading algorithm with the ``neo_usd`` currency pair
|
We are choosing to backtest this trading algorithm with the ``neo_usd`` currency
|
||||||
on the ``Bitfinex`` exchange. Thus, first ingest the historical pricing data
|
pairon the ``Bitfinex`` exchange. Thus, first ingest the historical pricing data
|
||||||
that we need, with minute resolution:
|
that we need, with minute resolution:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@@ -201,6 +466,11 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import talib
|
import talib
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
@@ -208,14 +478,16 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
from catalyst import run_algorithm
|
from catalyst import run_algorithm
|
||||||
from catalyst.api import symbol, record, order_target_percent, get_open_orders
|
from catalyst.api import symbol, record, order_target_percent, get_open_orders
|
||||||
from catalyst.exchange.stats_utils import extract_transactions
|
from catalyst.exchange.stats_utils import extract_transactions
|
||||||
|
|
||||||
# We give a name to the algorithm which Catalyst will use to persist its state.
|
# 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`
|
# In this example, Catalyst will create the `.catalyst/data/live_algos`
|
||||||
# directory. If we stop and start the algorithm, Catalyst will resume its
|
# directory. If we stop and start the algorithm, Catalyst will resume its
|
||||||
# state using the files included in the folder.
|
# state using the files included in the folder.
|
||||||
|
from catalyst.utils.paths import ensure_directory
|
||||||
|
|
||||||
NAMESPACE = 'mean_reversion_simple'
|
NAMESPACE = 'mean_reversion_simple'
|
||||||
log = Logger(NAMESPACE)
|
log = Logger(NAMESPACE)
|
||||||
|
|
||||||
|
|
||||||
# To run an algorithm in Catalyst, you need two functions: initialize and
|
# To run an algorithm in Catalyst, you need two functions: initialize and
|
||||||
# handle_data.
|
# handle_data.
|
||||||
|
|
||||||
@@ -225,11 +497,17 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
# trading pairs) you want to backtest. You'll also want to define any
|
# trading pairs) you want to backtest. You'll also want to define any
|
||||||
# parameters or values you're going to use.
|
# parameters or values you're going to use.
|
||||||
|
|
||||||
# In our example, we're looking at Ether in USD Tether.
|
# In our example, we're looking at Neo in USD.
|
||||||
context.neo_usd = symbol('neo_usd')
|
context.neo_eth = symbol('neo_usd')
|
||||||
context.base_price = None
|
context.base_price = None
|
||||||
context.current_day = None
|
context.current_day = None
|
||||||
|
|
||||||
|
context.RSI_OVERSOLD = 30
|
||||||
|
context.RSI_OVERBOUGHT = 80
|
||||||
|
context.CANDLE_SIZE = '15T'
|
||||||
|
|
||||||
|
context.start_time = time.time()
|
||||||
|
|
||||||
|
|
||||||
def handle_data(context, data):
|
def handle_data(context, data):
|
||||||
# This handle_data function is where the real work is done. Our data is
|
# This handle_data function is where the real work is done. Our data is
|
||||||
@@ -246,17 +524,17 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
context.current_day = today
|
context.current_day = today
|
||||||
|
|
||||||
# We're computing the volume-weighted-average-price of the security
|
# We're computing the volume-weighted-average-price of the security
|
||||||
# defined above, in the context.neo_usd variable. For this example, we're
|
# defined above, in the context.neo_eth variable. For this example, we're
|
||||||
# using three bars on the 15 min bars.
|
# using three bars on the 15 min bars.
|
||||||
|
|
||||||
# The frequency attribute determine the bar size. We use this convention
|
# The frequency attribute determine the bar size. We use this convention
|
||||||
# for the frequency alias:
|
# for the frequency alias:
|
||||||
# http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
|
# http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
|
||||||
prices = data.history(
|
prices = data.history(
|
||||||
context.neo_usd,
|
context.neo_eth,
|
||||||
fields='close',
|
fields='close',
|
||||||
bar_count=50,
|
bar_count=50,
|
||||||
frequency='15T'
|
frequency=context.CANDLE_SIZE
|
||||||
)
|
)
|
||||||
|
|
||||||
# Ta-lib calculates various technical indicator based on price and
|
# Ta-lib calculates various technical indicator based on price and
|
||||||
@@ -268,7 +546,7 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
# We need a variable for the current price of the security to compare to
|
# We need a variable for the current price of the security to compare to
|
||||||
# the average. Since we are requesting two fields, data.current()
|
# the average. Since we are requesting two fields, data.current()
|
||||||
# returns a DataFrame with
|
# returns a DataFrame with
|
||||||
current = data.current(context.neo_usd, fields=['close', 'volume'])
|
current = data.current(context.neo_eth, fields=['close', 'volume'])
|
||||||
price = current['close']
|
price = current['close']
|
||||||
|
|
||||||
# If base_price is not set, we use the current value. This is the
|
# If base_price is not set, we use the current value. This is the
|
||||||
@@ -297,56 +575,65 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
|
|
||||||
# Since we are using limit orders, some orders may not execute immediately
|
# Since we are using limit orders, some orders may not execute immediately
|
||||||
# we wait until all orders are executed before considering more trades.
|
# we wait until all orders are executed before considering more trades.
|
||||||
orders = get_open_orders(context.neo_usd)
|
orders = get_open_orders(context.neo_eth)
|
||||||
if len(orders) > 0:
|
if len(orders) > 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Exit if we cannot trade
|
# Exit if we cannot trade
|
||||||
if not data.can_trade(context.neo_usd):
|
if not data.can_trade(context.neo_eth):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Another powerful built-in feature of the Catalyst backtester is the
|
# Another powerful built-in feature of the Catalyst backtester is the
|
||||||
# portfolio object. The portfolio object tracks your positions, cash,
|
# portfolio object. The portfolio object tracks your positions, cash,
|
||||||
# cost basis of specific holdings, and more. In this line, we calculate
|
# cost basis of specific holdings, and more. In this line, we calculate
|
||||||
# how long or short our position is at this minute.
|
# how long or short our position is at this minute.
|
||||||
pos_amount = context.portfolio.positions[context.neo_usd].amount
|
pos_amount = context.portfolio.positions[context.neo_eth].amount
|
||||||
|
|
||||||
if rsi[-1] <= 30 and pos_amount == 0:
|
if rsi[-1] <= context.RSI_OVERSOLD and pos_amount == 0:
|
||||||
log.info(
|
log.info(
|
||||||
'{}: buying - price: {}, rsi: {}'.format(
|
'{}: buying - price: {}, rsi: {}'.format(
|
||||||
data.current_dt, price, rsi[-1]
|
data.current_dt, price, rsi[-1]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
order_target_percent(context.neo_usd, 1)
|
# Set a style for limit orders,
|
||||||
|
limit_price = price * 1.005
|
||||||
|
order_target_percent(
|
||||||
|
context.neo_eth, 1, limit_price=limit_price
|
||||||
|
)
|
||||||
context.traded_today = True
|
context.traded_today = True
|
||||||
|
|
||||||
elif rsi[-1] >= 80 and pos_amount > 0:
|
elif rsi[-1] >= context.RSI_OVERBOUGHT and pos_amount > 0:
|
||||||
log.info(
|
log.info(
|
||||||
'{}: selling - price: {}, rsi: {}'.format(
|
'{}: selling - price: {}, rsi: {}'.format(
|
||||||
data.current_dt, price, rsi[-1]
|
data.current_dt, price, rsi[-1]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
order_target_percent(context.neo_usd, 0)
|
limit_price = price * 0.995
|
||||||
|
order_target_percent(
|
||||||
|
context.neo_eth, 0, limit_price=limit_price
|
||||||
|
)
|
||||||
context.traded_today = True
|
context.traded_today = True
|
||||||
|
|
||||||
|
|
||||||
def analyze(context=None, perf=None):
|
def analyze(context=None, perf=None):
|
||||||
import matplotlib.pyplot as plt
|
end = time.time()
|
||||||
|
log.info('elapsed time: {}'.format(end - context.start_time))
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
# The base currency of the algo exchange
|
# The base currency of the algo exchange
|
||||||
base_currency = context.exchanges.values()[0].base_currency.upper()
|
base_currency = context.exchanges.values()[0].base_currency.upper()
|
||||||
|
|
||||||
# Plot the portfolio value over time.
|
# Plot the portfolio value over time.
|
||||||
ax1 = plt.subplot(611)
|
ax1 = plt.subplot(611)
|
||||||
perf.loc[:, 'portfolio_value'].plot(ax=ax1)
|
perf.loc[:, 'portfolio_value'].plot(ax=ax1)
|
||||||
ax1.set_ylabel('Portfolio Value ({})'.format(base_currency))
|
ax1.set_ylabel('Portfolio\nValue\n({})'.format(base_currency))
|
||||||
|
|
||||||
# Plot the price increase or decrease over time.
|
# Plot the price increase or decrease over time.
|
||||||
ax2 = plt.subplot(612, sharex=ax1)
|
ax2 = plt.subplot(612, sharex=ax1)
|
||||||
perf.loc[:, 'price'].plot(ax=ax2, label='Price')
|
perf.loc[:, 'price'].plot(ax=ax2, label='Price')
|
||||||
|
|
||||||
ax2.set_ylabel('{asset} ({base})'.format(
|
ax2.set_ylabel('{asset}\n({base})'.format(
|
||||||
asset=context.neo_usd.symbol, base=base_currency
|
asset=context.neo_eth.symbol, base=base_currency
|
||||||
))
|
))
|
||||||
|
|
||||||
transaction_df = extract_transactions(perf)
|
transaction_df = extract_transactions(perf)
|
||||||
@@ -355,7 +642,7 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
sell_df = transaction_df[transaction_df['amount'] < 0]
|
sell_df = transaction_df[transaction_df['amount'] < 0]
|
||||||
ax2.scatter(
|
ax2.scatter(
|
||||||
buy_df.index.to_pydatetime(),
|
buy_df.index.to_pydatetime(),
|
||||||
perf.loc[buy_df.index, 'price'],
|
perf.loc[buy_df.index.floor('1 min'), 'price'],
|
||||||
marker='^',
|
marker='^',
|
||||||
s=100,
|
s=100,
|
||||||
c='green',
|
c='green',
|
||||||
@@ -363,7 +650,7 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
)
|
)
|
||||||
ax2.scatter(
|
ax2.scatter(
|
||||||
sell_df.index.to_pydatetime(),
|
sell_df.index.to_pydatetime(),
|
||||||
perf.loc[sell_df.index, 'price'],
|
perf.loc[sell_df.index.floor('1 min'), 'price'],
|
||||||
marker='v',
|
marker='v',
|
||||||
s=100,
|
s=100,
|
||||||
c='red',
|
c='red',
|
||||||
@@ -374,23 +661,24 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
perf.loc[:, 'cash'].plot(
|
perf.loc[:, 'cash'].plot(
|
||||||
ax=ax4, label='Base Currency ({})'.format(base_currency)
|
ax=ax4, label='Base Currency ({})'.format(base_currency)
|
||||||
)
|
)
|
||||||
ax4.set_ylabel('Cash ({})'.format(base_currency))
|
ax4.set_ylabel('Cash\n({})'.format(base_currency))
|
||||||
|
|
||||||
perf['algorithm'] = perf.loc[:, 'algorithm_period_return']
|
perf['algorithm'] = perf.loc[:, 'algorithm_period_return']
|
||||||
|
|
||||||
ax5 = plt.subplot(614, sharex=ax1)
|
ax5 = plt.subplot(614, sharex=ax1)
|
||||||
perf.loc[:, ['algorithm', 'price_change']].plot(ax=ax5)
|
perf.loc[:, ['algorithm', 'price_change']].plot(ax=ax5)
|
||||||
ax5.set_ylabel('Percent Change')
|
ax5.set_ylabel('Percent\nChange')
|
||||||
|
|
||||||
ax6 = plt.subplot(615, sharex=ax1)
|
ax6 = plt.subplot(615, sharex=ax1)
|
||||||
perf.loc[:, 'rsi'].plot(ax=ax6, label='RSI')
|
perf.loc[:, 'rsi'].plot(ax=ax6, label='RSI')
|
||||||
ax6.axhline(70, color='darkgoldenrod')
|
ax6.set_ylabel('RSI')
|
||||||
ax6.axhline(30, color='darkgoldenrod')
|
ax6.axhline(context.RSI_OVERBOUGHT, color='darkgoldenrod')
|
||||||
|
ax6.axhline(context.RSI_OVERSOLD, color='darkgoldenrod')
|
||||||
|
|
||||||
if not transaction_df.empty:
|
if not transaction_df.empty:
|
||||||
ax6.scatter(
|
ax6.scatter(
|
||||||
buy_df.index.to_pydatetime(),
|
buy_df.index.to_pydatetime(),
|
||||||
perf.loc[buy_df.index, 'rsi'],
|
perf.loc[buy_df.index.floor('1 min'), 'rsi'],
|
||||||
marker='^',
|
marker='^',
|
||||||
s=100,
|
s=100,
|
||||||
c='green',
|
c='green',
|
||||||
@@ -398,13 +686,15 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
)
|
)
|
||||||
ax6.scatter(
|
ax6.scatter(
|
||||||
sell_df.index.to_pydatetime(),
|
sell_df.index.to_pydatetime(),
|
||||||
perf.loc[sell_df.index, 'rsi'],
|
perf.loc[sell_df.index.floor('1 min'), 'rsi'],
|
||||||
marker='v',
|
marker='v',
|
||||||
s=100,
|
s=100,
|
||||||
c='red',
|
c='red',
|
||||||
label=''
|
label=''
|
||||||
)
|
)
|
||||||
plt.legend(loc=3)
|
plt.legend(loc=3)
|
||||||
|
start, end = ax6.get_ylim()
|
||||||
|
ax6.yaxis.set_ticks(np.arange(0, end, end/5))
|
||||||
|
|
||||||
# Show the plot.
|
# Show the plot.
|
||||||
plt.gcf().set_size_inches(18, 8)
|
plt.gcf().set_size_inches(18, 8)
|
||||||
@@ -417,7 +707,14 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
MODE = 'backtest'
|
MODE = 'backtest'
|
||||||
|
|
||||||
if MODE == 'backtest':
|
if MODE == 'backtest':
|
||||||
# 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
|
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(
|
run_algorithm(
|
||||||
capital_base=10000,
|
capital_base=10000,
|
||||||
data_frequency='minute',
|
data_frequency='minute',
|
||||||
@@ -427,18 +724,178 @@ lines 218-245, so in order to run the algorithm we just type:
|
|||||||
exchange_name='bitfinex',
|
exchange_name='bitfinex',
|
||||||
algo_namespace=NAMESPACE,
|
algo_namespace=NAMESPACE,
|
||||||
base_currency='usd',
|
base_currency='usd',
|
||||||
start=pd.to_datetime('2017-10-1', utc=True),
|
start=pd.to_datetime('2017-10-01', utc=True),
|
||||||
end=pd.to_datetime('2017-11-10', utc=True),
|
end=pd.to_datetime('2017-11-10', utc=True),
|
||||||
|
output=out
|
||||||
)
|
)
|
||||||
|
log.info('saved perf stats: {}'.format(out))
|
||||||
|
|
||||||
elif MODE == 'live':
|
elif MODE == 'live':
|
||||||
run_algorithm(
|
run_algorithm(
|
||||||
|
capital_base=0.5,
|
||||||
initialize=initialize,
|
initialize=initialize,
|
||||||
handle_data=handle_data,
|
handle_data=handle_data,
|
||||||
analyze=analyze,
|
analyze=analyze,
|
||||||
exchange_name='bitfinex',
|
exchange_name='bittrex',
|
||||||
live=True,
|
live=True,
|
||||||
algo_namespace=NAMESPACE,
|
algo_namespace=NAMESPACE,
|
||||||
base_currency='usd',
|
base_currency='usd',
|
||||||
live_graph=True
|
live_graph=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
.. image:: https://s3.amazonaws.com/enigmaco-docs/github.io/example_mean_reversion_simple.png
|
||||||
|
|
||||||
|
Notice the difference in performance between the charts above and those seen on
|
||||||
|
`this video tutorial <https://youtu.be/JOBRwst9jUY>`_ 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.
|
||||||
|
|
||||||
|
.. _portfolio_optimization:
|
||||||
|
|
||||||
|
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 <https://blog.enigma.co/markowitz-portfolio-optimization-for-cryptocurrencies-in-catalyst-b23c38652556>`_.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
'''
|
||||||
|
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
|
||||||
|
from scipy.optimize import minimize
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from catalyst.api import record, symbol, symbols, order_target_percent
|
||||||
|
from catalyst.utils.run_algo import run_algorithm
|
||||||
|
|
||||||
|
np.set_printoptions(threshold='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 beggining 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 xrange(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]
|
||||||
|
i = 0
|
||||||
|
for iw in weights:
|
||||||
|
results_array[3+i,p] = weights[i]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
#convert results array to Pandas DataFrame
|
||||||
|
results_frame = pd.DataFrame(np.transpose(results_array),
|
||||||
|
columns=['r','stdev','sharpe']+context.assets)
|
||||||
|
#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:
|
||||||
|
if data.can_trade(asset):
|
||||||
|
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 red star 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)
|
||||||
|
#plot green star to highlight position of minimum variance portfolio
|
||||||
|
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')
|
||||||
|
|
||||||
|
|
||||||
|
# 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, )
|
||||||
|
|
||||||
|
.. image:: https://cdn-images-1.medium.com/max/1600/0*EjjiKZHlYF3sn7yQ.
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+17
-1
@@ -32,7 +32,9 @@ Where things don't:
|
|||||||
Backtesting a Strategy
|
Backtesting a Strategy
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
This algorithm is based on a simple momentum strategy. When the cryptoasset
|
This is the first video of a two-part series on using Catalyst for algorithmic
|
||||||
|
trading. This video implements a simple momentum strategy based on
|
||||||
|
`mean reversion <example-algos.html#mean-reversion>`_: when the cryptoasset
|
||||||
goes up quickly, we’re going to buy; when it goes down quickly, we’re going to
|
goes up quickly, we’re going to buy; when it goes down quickly, we’re going to
|
||||||
sell. Hopefully, we’ll ride the waves.
|
sell. Hopefully, we’ll ride the waves.
|
||||||
|
|
||||||
@@ -40,3 +42,17 @@ sell. Hopefully, we’ll ride the waves.
|
|||||||
|
|
||||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/JOBRwst9jUY" frameborder="0" allowfullscreen></iframe>
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/JOBRwst9jUY" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
Live Trading a Strategy
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
This is the second part of the two-part series on using Catalyst for algorithmic
|
||||||
|
trading. Having backtested `our strategy <example-algos.html#mean-reversion>`_
|
||||||
|
in the previous video, we now take it to trade live against the Bittrex exchange.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<iframe width="560" height="315" src="https://www.youtube.com/embed/NupiE-Xuglw" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
|
||||||
|
|
|
||||||
@@ -105,7 +105,7 @@ None
|
|||||||
Miscellaneous
|
Miscellaneous
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
* Adds :class:`~zipline.testing.fixtures.ZiplineTestCase` which provides hooks
|
* Adds :class:`~zipline.testing.fixtures.CatalystTestCase` which provides hooks
|
||||||
to consume test fixtures. Fixtures are things like:
|
to consume test fixtures. Fixtures are things like:
|
||||||
:class:`~zipline.testing.fixtures.WithAssetFinder` which will make
|
:class:`~zipline.testing.fixtures.WithAssetFinder` which will make
|
||||||
``self.asset_finder`` available to your test with some mock data
|
``self.asset_finder`` available to your test with some mock data
|
||||||
|
|||||||
@@ -80,3 +80,6 @@ empyrical==0.2.1
|
|||||||
|
|
||||||
tables==3.3.0
|
tables==3.3.0
|
||||||
|
|
||||||
|
#Catalyst dependencies
|
||||||
|
ccxt==1.10.251
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ from catalyst.errors import (
|
|||||||
CyclicCalendarAlias,
|
CyclicCalendarAlias,
|
||||||
InvalidCalendarName,
|
InvalidCalendarName,
|
||||||
)
|
)
|
||||||
from catalyst.testing import ZiplineTestCase
|
from catalyst.testing import CatalystTestCase
|
||||||
from catalyst.utils.calendars.calendar_utils import TradingCalendarDispatcher
|
from catalyst.utils.calendars.calendar_utils import TradingCalendarDispatcher
|
||||||
from catalyst.utils.calendars.exchange_calendar_ice import ICEExchangeCalendar
|
from catalyst.utils.calendars.exchange_calendar_ice import ICEExchangeCalendar
|
||||||
|
|
||||||
|
|
||||||
class CalendarAliasTestCase(ZiplineTestCase):
|
class CalendarAliasTestCase(CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def init_class_fixtures(cls):
|
def init_class_fixtures(cls):
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from catalyst.testing import (
|
|||||||
subtest,
|
subtest,
|
||||||
str_to_seconds,
|
str_to_seconds,
|
||||||
)
|
)
|
||||||
from catalyst.testing.fixtures import WithInstanceTmpDir, ZiplineTestCase, \
|
from catalyst.testing.fixtures import WithInstanceTmpDir, CatalystTestCase, \
|
||||||
WithDefaultDateBounds
|
WithDefaultDateBounds
|
||||||
from catalyst.testing.predicates import (
|
from catalyst.testing.predicates import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
@@ -45,7 +45,7 @@ _1_ns = pd.Timedelta(1, unit='ns')
|
|||||||
|
|
||||||
class BundleCoreTestCase(WithInstanceTmpDir,
|
class BundleCoreTestCase(WithInstanceTmpDir,
|
||||||
WithDefaultDateBounds,
|
WithDefaultDateBounds,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
START_DATE = pd.Timestamp('2014-01-06', tz='utc')
|
START_DATE = pd.Timestamp('2014-01-06', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2014-01-10', tz='utc')
|
END_DATE = pd.Timestamp('2014-01-10', tz='utc')
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ from catalyst.testing import (
|
|||||||
tmp_dir,
|
tmp_dir,
|
||||||
patch_read_csv,
|
patch_read_csv,
|
||||||
)
|
)
|
||||||
from catalyst.testing.fixtures import ZiplineTestCase
|
from catalyst.testing.fixtures import CatalystTestCase
|
||||||
from catalyst.testing.predicates import (
|
from catalyst.testing.predicates import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
)
|
)
|
||||||
from catalyst.utils.functional import apply
|
from catalyst.utils.functional import apply
|
||||||
|
|
||||||
|
|
||||||
class QuandlBundleTestCase(ZiplineTestCase):
|
class QuandlBundleTestCase(CatalystTestCase):
|
||||||
symbols = 'AAPL', 'BRK_A', 'MSFT', 'ZEN'
|
symbols = 'AAPL', 'BRK_A', 'MSFT', 'ZEN'
|
||||||
asset_start = pd.Timestamp('2014-01', tz='utc')
|
asset_start = pd.Timestamp('2014-01', tz='utc')
|
||||||
asset_end = pd.Timestamp('2015-01', tz='utc')
|
asset_end = pd.Timestamp('2015-01', tz='utc')
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ from catalyst.data.bundles.core import _make_bundle_core
|
|||||||
from catalyst.data.bundles import yahoo_equities
|
from catalyst.data.bundles import yahoo_equities
|
||||||
from catalyst.lib.adjustment import Float64Multiply
|
from catalyst.lib.adjustment import Float64Multiply
|
||||||
from catalyst.testing import test_resource_path, tmp_dir, read_compressed
|
from catalyst.testing import test_resource_path, tmp_dir, read_compressed
|
||||||
from catalyst.testing.fixtures import WithResponses, ZiplineTestCase
|
from catalyst.testing.fixtures import WithResponses, CatalystTestCase
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.utils.calendars import get_calendar
|
from catalyst.utils.calendars import get_calendar
|
||||||
|
|
||||||
|
|
||||||
class YahooBundleTestCase(WithResponses, ZiplineTestCase):
|
class YahooBundleTestCase(WithResponses, CatalystTestCase):
|
||||||
symbols = 'AAPL', 'IBM', 'MSFT'
|
symbols = 'AAPL', 'IBM', 'MSFT'
|
||||||
columns = 'open', 'high', 'low', 'close', 'volume'
|
columns = 'open', 'high', 'low', 'close', 'volume'
|
||||||
asset_start = pd.Timestamp('2014-01-02', tz='utc')
|
asset_start = pd.Timestamp('2014-01-02', tz='utc')
|
||||||
|
|||||||
@@ -11,6 +11,12 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
# ZIPLINE legacy test: Catalyst does not use DispatchBarReader, and thus
|
||||||
|
# this test suite is irrelevant, and is commented out in its entirety
|
||||||
|
|
||||||
from numpy import array, nan
|
from numpy import array, nan
|
||||||
from numpy.testing import assert_almost_equal
|
from numpy.testing import assert_almost_equal
|
||||||
from pandas import DataFrame, Timestamp
|
from pandas import DataFrame, Timestamp
|
||||||
@@ -31,7 +37,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithBcolzEquityDailyBarReader,
|
WithBcolzEquityDailyBarReader,
|
||||||
WithBcolzFutureMinuteBarReader,
|
WithBcolzFutureMinuteBarReader,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
OHLC = ['open', 'high', 'low', 'close']
|
OHLC = ['open', 'high', 'low', 'close']
|
||||||
@@ -40,7 +46,7 @@ OHLC = ['open', 'high', 'low', 'close']
|
|||||||
class AssetDispatchSessionBarTestCase(WithBcolzEquityDailyBarReader,
|
class AssetDispatchSessionBarTestCase(WithBcolzEquityDailyBarReader,
|
||||||
WithBcolzFutureMinuteBarReader,
|
WithBcolzFutureMinuteBarReader,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
TRADING_CALENDAR_STRS = ('us_futures', 'NYSE')
|
TRADING_CALENDAR_STRS = ('us_futures', 'NYSE')
|
||||||
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
||||||
@@ -169,7 +175,7 @@ class AssetDispatchSessionBarTestCase(WithBcolzEquityDailyBarReader,
|
|||||||
|
|
||||||
class AssetDispatchMinuteBarTestCase(WithBcolzEquityMinuteBarReader,
|
class AssetDispatchMinuteBarTestCase(WithBcolzEquityMinuteBarReader,
|
||||||
WithBcolzFutureMinuteBarReader,
|
WithBcolzFutureMinuteBarReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
TRADING_CALENDAR_STRS = ('us_futures', 'NYSE')
|
TRADING_CALENDAR_STRS = ('us_futures', 'NYSE')
|
||||||
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
||||||
@@ -330,3 +336,4 @@ class AssetDispatchMinuteBarTestCase(WithBcolzEquityMinuteBarReader,
|
|||||||
for i, (sid, expected, msg) in enumerate(expected_per_sid):
|
for i, (sid, expected, msg) in enumerate(expected_per_sid):
|
||||||
for j, result in enumerate(results):
|
for j, result in enumerate(results):
|
||||||
assert_almost_equal(result[:, i], expected[j], err_msg=msg)
|
assert_almost_equal(result[:, i], expected[j], err_msg=msg)
|
||||||
|
'''
|
||||||
@@ -38,8 +38,8 @@ from pandas import (
|
|||||||
from catalyst.data.bar_reader import NoDataOnDate
|
from catalyst.data.bar_reader import NoDataOnDate
|
||||||
from catalyst.data.minute_bars import (
|
from catalyst.data.minute_bars import (
|
||||||
BcolzMinuteBarMetadata,
|
BcolzMinuteBarMetadata,
|
||||||
BcolzMinuteBarWriter,
|
# BcolzMinuteBarWriter,
|
||||||
BcolzMinuteBarReader,
|
# BcolzMinuteBarReader,
|
||||||
BcolzMinuteOverlappingData,
|
BcolzMinuteOverlappingData,
|
||||||
US_EQUITIES_MINUTES_PER_DAY,
|
US_EQUITIES_MINUTES_PER_DAY,
|
||||||
BcolzMinuteWriterColumnMismatch,
|
BcolzMinuteWriterColumnMismatch,
|
||||||
@@ -47,24 +47,29 @@ from catalyst.data.minute_bars import (
|
|||||||
H5MinuteBarUpdateReader,
|
H5MinuteBarUpdateReader,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from catalyst.exchange.exchange_bcolz import (
|
||||||
|
BcolzExchangeBarWriter,
|
||||||
|
BcolzExchangeBarReader,
|
||||||
|
)
|
||||||
|
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithAssetFinder,
|
WithAssetFinder,
|
||||||
WithInstanceTmpDir,
|
WithInstanceTmpDir,
|
||||||
WithTradingCalendars,
|
WithTradingCalendars,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calendar is set to cover several half days, to check a case where half
|
# Calendar is set to cover several half days, to check a case where half
|
||||||
# days would be read out of order in cases of windows which spanned over
|
# days would be read out of order in cases of windows which spanned over
|
||||||
# multiple half days.
|
# multiple half days.
|
||||||
TEST_CALENDAR_START = Timestamp('2014-06-02', tz='UTC')
|
TEST_CALENDAR_START = Timestamp('2015-06-02', tz='UTC')
|
||||||
TEST_CALENDAR_STOP = Timestamp('2015-12-31', tz='UTC')
|
TEST_CALENDAR_STOP = Timestamp('2016-12-31', tz='UTC')
|
||||||
|
|
||||||
|
|
||||||
class BcolzMinuteBarTestCase(WithTradingCalendars,
|
class BcolzMinuteBarTestCase(WithTradingCalendars,
|
||||||
WithAssetFinder,
|
WithAssetFinder,
|
||||||
WithInstanceTmpDir,
|
WithInstanceTmpDir,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
ASSET_FINDER_EQUITY_SIDS = 1, 2
|
ASSET_FINDER_EQUITY_SIDS = 1, 2
|
||||||
|
|
||||||
@@ -87,14 +92,14 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
|
|
||||||
self.dest = self.instance_tmpdir.getpath('minute_bars')
|
self.dest = self.instance_tmpdir.getpath('minute_bars')
|
||||||
os.makedirs(self.dest)
|
os.makedirs(self.dest)
|
||||||
self.writer = BcolzMinuteBarWriter(
|
self.writer = BcolzExchangeBarWriter(
|
||||||
self.dest,
|
rootdir=self.dest,
|
||||||
self.trading_calendar,
|
calendar=self.trading_calendar,
|
||||||
TEST_CALENDAR_START,
|
start_session=TEST_CALENDAR_START,
|
||||||
TEST_CALENDAR_STOP,
|
end_session=TEST_CALENDAR_STOP,
|
||||||
US_EQUITIES_MINUTES_PER_DAY,
|
data_frequency='minute',
|
||||||
)
|
)
|
||||||
self.reader = BcolzMinuteBarReader(self.dest)
|
self.reader = BcolzExchangeBarReader(self.dest)
|
||||||
|
|
||||||
def test_version(self):
|
def test_version(self):
|
||||||
metadata = self.reader._get_metadata()
|
metadata = self.reader._get_metadata()
|
||||||
@@ -152,7 +157,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Create a new writer with `ohlc_ratios_per_sid` defined.
|
# Create a new writer with `ohlc_ratios_per_sid` defined.
|
||||||
writer_with_ratios = BcolzMinuteBarWriter(
|
writer_with_ratios = BcolzExchangeBarWriter(
|
||||||
self.dest,
|
self.dest,
|
||||||
self.trading_calendar,
|
self.trading_calendar,
|
||||||
TEST_CALENDAR_START,
|
TEST_CALENDAR_START,
|
||||||
@@ -161,7 +166,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
ohlc_ratios_per_sid={sid: 25},
|
ohlc_ratios_per_sid={sid: 25},
|
||||||
)
|
)
|
||||||
writer_with_ratios.write_sid(sid, data)
|
writer_with_ratios.write_sid(sid, data)
|
||||||
reader = BcolzMinuteBarReader(self.dest)
|
reader = BcolzExchangeBarReader(self.dest)
|
||||||
|
|
||||||
open_price = reader.get_value(sid, minute, 'open')
|
open_price = reader.get_value(sid, minute, 'open')
|
||||||
self.assertEquals(10.0, open_price)
|
self.assertEquals(10.0, open_price)
|
||||||
@@ -449,7 +454,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
# of appending new days will be writing to an existing directory.
|
# of appending new days will be writing to an existing directory.
|
||||||
cday = self.trading_calendar.schedule.index.freq
|
cday = self.trading_calendar.schedule.index.freq
|
||||||
new_end_session = TEST_CALENDAR_STOP + cday
|
new_end_session = TEST_CALENDAR_STOP + cday
|
||||||
writer = BcolzMinuteBarWriter.open(self.dest, new_end_session)
|
writer = BcolzExchangeBarWriter.open(self.dest, new_end_session)
|
||||||
next_day_minute = dt + cday
|
next_day_minute = dt + cday
|
||||||
new_data = DataFrame(
|
new_data = DataFrame(
|
||||||
data=ohlcv,
|
data=ohlcv,
|
||||||
@@ -457,7 +462,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
writer.write_sid(sid, new_data)
|
writer.write_sid(sid, new_data)
|
||||||
|
|
||||||
# Get a new reader to test updated calendar.
|
# Get a new reader to test updated calendar.
|
||||||
reader = BcolzMinuteBarReader(self.dest)
|
reader = BcolzExchangeBarReader(self.dest)
|
||||||
|
|
||||||
second_minute = dt + Timedelta(minutes=1)
|
second_minute = dt + Timedelta(minutes=1)
|
||||||
|
|
||||||
@@ -802,7 +807,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
index=minutes)
|
index=minutes)
|
||||||
self.writer.write_sid(sids[1], data_2)
|
self.writer.write_sid(sids[1], data_2)
|
||||||
|
|
||||||
reader = BcolzMinuteBarReader(self.dest)
|
reader = BcolzExchangeBarReader(self.dest)
|
||||||
|
|
||||||
columns = ['open', 'high', 'low', 'close', 'volume']
|
columns = ['open', 'high', 'low', 'close', 'volume']
|
||||||
sids = [sids[0], sids[1]]
|
sids = [sids[0], sids[1]]
|
||||||
@@ -854,7 +859,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
index=minutes)
|
index=minutes)
|
||||||
self.writer.write_sid(sids[1], data_2)
|
self.writer.write_sid(sids[1], data_2)
|
||||||
|
|
||||||
reader = BcolzMinuteBarReader(self.dest)
|
reader = BcolzExchangeBarReader(self.dest)
|
||||||
|
|
||||||
columns = ['open', 'high', 'low', 'close', 'volume']
|
columns = ['open', 'high', 'low', 'close', 'volume']
|
||||||
sids = [sids[0], sids[1]]
|
sids = [sids[0], sids[1]]
|
||||||
@@ -877,6 +882,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
assert_almost_equal(data[sid].loc[minutes, col],
|
assert_almost_equal(data[sid].loc[minutes, col],
|
||||||
arrays[i][j][minute_locs])
|
arrays[i][j][minute_locs])
|
||||||
|
|
||||||
|
'''
|
||||||
def test_adjust_non_trading_minutes(self):
|
def test_adjust_non_trading_minutes(self):
|
||||||
start_day = Timestamp('2015-06-01', tz='UTC')
|
start_day = Timestamp('2015-06-01', tz='UTC')
|
||||||
end_day = Timestamp('2015-06-02', tz='UTC')
|
end_day = Timestamp('2015-06-02', tz='UTC')
|
||||||
@@ -922,7 +928,9 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
Timestamp('2015-06-02 20:01:00', tz='UTC'),
|
Timestamp('2015-06-02 20:01:00', tz='UTC'),
|
||||||
'open'
|
'open'
|
||||||
)
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
def test_adjust_non_trading_minutes_half_days(self):
|
def test_adjust_non_trading_minutes_half_days(self):
|
||||||
# half day
|
# half day
|
||||||
start_day = Timestamp('2015-11-27', tz='UTC')
|
start_day = Timestamp('2015-11-27', tz='UTC')
|
||||||
@@ -978,6 +986,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
Timestamp('2015-11-30 21:01:00', tz='UTC'),
|
Timestamp('2015-11-30 21:01:00', tz='UTC'),
|
||||||
'open'
|
'open'
|
||||||
)
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
def test_set_sid_attrs(self):
|
def test_set_sid_attrs(self):
|
||||||
"""Confirm that we can set the attributes of a sid's file correctly.
|
"""Confirm that we can set the attributes of a sid's file correctly.
|
||||||
@@ -1023,13 +1032,13 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
|
|
||||||
# Open a new writer to cover `open` method, also truncating only
|
# Open a new writer to cover `open` method, also truncating only
|
||||||
# applies to an existing directory.
|
# applies to an existing directory.
|
||||||
writer = BcolzMinuteBarWriter.open(self.dest)
|
writer = BcolzExchangeBarWriter.open(self.dest)
|
||||||
|
|
||||||
# Truncate to first day with data.
|
# Truncate to first day with data.
|
||||||
writer.truncate(days[0])
|
writer.truncate(days[0])
|
||||||
|
|
||||||
# Refresh the reader since truncate update the metadata.
|
# Refresh the reader since truncate update the metadata.
|
||||||
self.reader = BcolzMinuteBarReader(self.dest)
|
self.reader = BcolzExchangeBarReader(self.dest)
|
||||||
|
|
||||||
self.assertEqual(self.writer.last_date_in_output_for_sid(sid), days[0])
|
self.assertEqual(self.writer.last_date_in_output_for_sid(sid), days[0])
|
||||||
|
|
||||||
@@ -1087,7 +1096,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
self.writer.truncate(self.test_calendar_start)
|
self.writer.truncate(self.test_calendar_start)
|
||||||
|
|
||||||
# Refresh the reader since truncate update the metadata.
|
# Refresh the reader since truncate update the metadata.
|
||||||
self.reader = BcolzMinuteBarReader(self.dest)
|
self.reader = BcolzExchangeBarReader(self.dest)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.writer.last_date_in_output_for_sid(sid),
|
self.writer.last_date_in_output_for_sid(sid),
|
||||||
@@ -1198,7 +1207,7 @@ class BcolzMinuteBarTestCase(WithTradingCalendars,
|
|||||||
self.writer.write(update_reader.read(minutes, sids))
|
self.writer.write(update_reader.read(minutes, sids))
|
||||||
|
|
||||||
# Refresh the reader since truncate update the metadata.
|
# Refresh the reader since truncate update the metadata.
|
||||||
reader = BcolzMinuteBarReader(self.dest)
|
reader = BcolzExchangeBarReader(self.dest)
|
||||||
|
|
||||||
columns = ['open', 'high', 'low', 'close', 'volume']
|
columns = ['open', 'high', 'low', 'close', 'volume']
|
||||||
sids = [sids[0], sids[1]]
|
sids = [sids[0], sids[1]]
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithBcolzEquityMinuteBarReader,
|
WithBcolzEquityMinuteBarReader,
|
||||||
WithBcolzEquityDailyBarReader,
|
WithBcolzEquityDailyBarReader,
|
||||||
WithBcolzFutureMinuteBarReader,
|
WithBcolzFutureMinuteBarReader,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
OHLC = ['open', 'high', 'low', 'close']
|
OHLC = ['open', 'high', 'low', 'close']
|
||||||
@@ -254,7 +254,7 @@ EXPECTED_SESSIONS = {
|
|||||||
|
|
||||||
class MinuteToDailyAggregationTestCase(WithBcolzEquityMinuteBarReader,
|
class MinuteToDailyAggregationTestCase(WithBcolzEquityMinuteBarReader,
|
||||||
WithBcolzFutureMinuteBarReader,
|
WithBcolzFutureMinuteBarReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
# March 2016
|
# March 2016
|
||||||
# Su Mo Tu We Th Fr Sa
|
# Su Mo Tu We Th Fr Sa
|
||||||
@@ -525,7 +525,7 @@ class MinuteToDailyAggregationTestCase(WithBcolzEquityMinuteBarReader,
|
|||||||
|
|
||||||
|
|
||||||
class TestMinuteToSession(WithEquityMinuteBarData,
|
class TestMinuteToSession(WithEquityMinuteBarData,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
# March 2016
|
# March 2016
|
||||||
# Su Mo Tu We Th Fr Sa
|
# Su Mo Tu We Th Fr Sa
|
||||||
@@ -565,7 +565,7 @@ class TestMinuteToSession(WithEquityMinuteBarData,
|
|||||||
|
|
||||||
|
|
||||||
class TestResampleSessionBars(WithBcolzFutureMinuteBarReader,
|
class TestResampleSessionBars(WithBcolzFutureMinuteBarReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
TRADING_CALENDAR_STRS = ('us_futures',)
|
TRADING_CALENDAR_STRS = ('us_futures',)
|
||||||
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
||||||
@@ -667,7 +667,7 @@ class TestResampleSessionBars(WithBcolzFutureMinuteBarReader,
|
|||||||
|
|
||||||
|
|
||||||
class TestReindexMinuteBars(WithBcolzEquityMinuteBarReader,
|
class TestReindexMinuteBars(WithBcolzEquityMinuteBarReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
TRADING_CALENDAR_STRS = ('us_futures', 'NYSE')
|
TRADING_CALENDAR_STRS = ('us_futures', 'NYSE')
|
||||||
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
||||||
@@ -736,7 +736,7 @@ class TestReindexMinuteBars(WithBcolzEquityMinuteBarReader,
|
|||||||
|
|
||||||
|
|
||||||
class TestReindexSessionBars(WithBcolzEquityDailyBarReader,
|
class TestReindexSessionBars(WithBcolzEquityDailyBarReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
TRADING_CALENDAR_STRS = ('us_futures', 'NYSE')
|
TRADING_CALENDAR_STRS = ('us_futures', 'NYSE')
|
||||||
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
TRADING_CALENDAR_PRIMARY_CAL = 'us_futures'
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithBcolzEquityDailyBarReader,
|
WithBcolzEquityDailyBarReader,
|
||||||
WithTmpDir,
|
WithTmpDir,
|
||||||
WithTradingCalendars,
|
WithTradingCalendars,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.calendars import get_calendar
|
from catalyst.utils.calendars import get_calendar
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ EQUITY_INFO['symbol'] = [chr(ord('A') + n) for n in range(len(EQUITY_INFO))]
|
|||||||
TEST_QUERY_ASSETS = EQUITY_INFO.index
|
TEST_QUERY_ASSETS = EQUITY_INFO.index
|
||||||
|
|
||||||
|
|
||||||
class BcolzDailyBarTestCase(WithBcolzEquityDailyBarReader, ZiplineTestCase):
|
class BcolzDailyBarTestCase(WithBcolzEquityDailyBarReader, CatalystTestCase):
|
||||||
EQUITY_DAILY_BAR_START_DATE = TEST_CALENDAR_START
|
EQUITY_DAILY_BAR_START_DATE = TEST_CALENDAR_START
|
||||||
EQUITY_DAILY_BAR_END_DATE = TEST_CALENDAR_STOP
|
EQUITY_DAILY_BAR_END_DATE = TEST_CALENDAR_STOP
|
||||||
|
|
||||||
@@ -372,7 +372,7 @@ class BcolzDailyBarNeverReadAllTestCase(BcolzDailyBarTestCase):
|
|||||||
class BcolzDailyBarWriterMissingDataTestCase(WithAssetFinder,
|
class BcolzDailyBarWriterMissingDataTestCase(WithAssetFinder,
|
||||||
WithTmpDir,
|
WithTmpDir,
|
||||||
WithTradingCalendars,
|
WithTradingCalendars,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
# Sid 3 is active from 2015-06-02 to 2015-06-30.
|
# Sid 3 is active from 2015-06-02 to 2015-06-30.
|
||||||
MISSING_DATA_SID = 3
|
MISSING_DATA_SID = 3
|
||||||
# Leave out data for a day in the middle of the query range.
|
# Leave out data for a day in the middle of the query range.
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
'''
|
||||||
|
# ZIPLINE legacy test: Catalyst only uses OPEN calendar, and thus
|
||||||
|
# this test suite is irrelevant, and is commented out in its entirety
|
||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
@@ -41,3 +46,5 @@ class TestStatelessRulesCME(StatelessRulesTests, TestCase):
|
|||||||
|
|
||||||
class TestStatefulRulesCME(StatefulRulesTests, TestCase):
|
class TestStatefulRulesCME(StatefulRulesTests, TestCase):
|
||||||
CALENDAR_STRING = "CME"
|
CALENDAR_STRING = "CME"
|
||||||
|
|
||||||
|
'''
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
'''
|
||||||
|
# ZIPLINE legacy test: Catalyst only uses OPEN calendar, and thus
|
||||||
|
# this test suite is irrelevant, and is commented out in its entirety
|
||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@@ -162,3 +167,5 @@ class TestStatelessRulesNYSE(StatelessRulesTests, TestCase):
|
|||||||
|
|
||||||
class TestStatefulRulesNYSE(StatefulRulesTests, TestCase):
|
class TestStatefulRulesNYSE(StatefulRulesTests, TestCase):
|
||||||
CALENDAR_STRING = "NYSE"
|
CALENDAR_STRING = "NYSE"
|
||||||
|
|
||||||
|
'''
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from catalyst.exchange.ccxt.ccxt_exchange import CCXT
|
||||||
|
from catalyst.finance.order import Order
|
||||||
|
from base import BaseExchangeTestCase
|
||||||
|
from logbook import Logger
|
||||||
|
from catalyst.exchange.exchange_utils import get_exchange_auth
|
||||||
|
from catalyst.utils.paths import ensure_directory
|
||||||
|
|
||||||
|
log = Logger('test_ccxt')
|
||||||
|
|
||||||
|
|
||||||
|
class TestCCXT(BaseExchangeTestCase):
|
||||||
|
@classmethod
|
||||||
|
def setup(self):
|
||||||
|
exchange_name = 'gdax'
|
||||||
|
auth = get_exchange_auth(exchange_name)
|
||||||
|
self.exchange = CCXT(
|
||||||
|
exchange_name=exchange_name,
|
||||||
|
key=auth['key'],
|
||||||
|
secret=auth['secret'],
|
||||||
|
base_currency='eth',
|
||||||
|
portfolio=None
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_order(self):
|
||||||
|
log.info('creating order')
|
||||||
|
asset = self.exchange.get_asset('neo_eth')
|
||||||
|
order_id = self.exchange.order(
|
||||||
|
asset=asset,
|
||||||
|
limit_price=0.07,
|
||||||
|
amount=1,
|
||||||
|
)
|
||||||
|
log.info('order created {}'.format(order_id))
|
||||||
|
assert order_id is not None
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_open_orders(self):
|
||||||
|
log.info('retrieving open orders')
|
||||||
|
asset = self.exchange.get_asset('neo_eth')
|
||||||
|
orders = self.exchange.get_open_orders(asset)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_get_order(self):
|
||||||
|
log.info('retrieving order')
|
||||||
|
order = self.exchange.get_order('2631386', 'neo_eth')
|
||||||
|
# order = self.exchange.get_order('2631386')
|
||||||
|
assert isinstance(order, Order)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_cancel_order(self, ):
|
||||||
|
log.info('cancel order')
|
||||||
|
self.exchange.cancel_order('2631386', 'neo_eth')
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_get_candles(self):
|
||||||
|
log.info('retrieving candles')
|
||||||
|
candles = self.exchange.get_candles(
|
||||||
|
freq='5T',
|
||||||
|
assets=[self.exchange.get_asset('eth_btc')],
|
||||||
|
bar_count=200,
|
||||||
|
start_dt=pd.to_datetime('2017-01-01', utc=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
for asset in candles:
|
||||||
|
df = pd.DataFrame(candles[asset])
|
||||||
|
df.set_index('last_traded', drop=True, inplace=True)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_tickers(self):
|
||||||
|
log.info('retrieving tickers')
|
||||||
|
tickers = self.exchange.tickers([
|
||||||
|
self.exchange.get_asset('eth_btc'),
|
||||||
|
])
|
||||||
|
assert len(tickers) == 1
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_get_balances(self):
|
||||||
|
log.info('testing wallet balances')
|
||||||
|
balances = self.exchange.get_balances()
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_get_account(self):
|
||||||
|
log.info('testing account data')
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_orderbook(self):
|
||||||
|
log.info('testing order book for bittrex')
|
||||||
|
asset = self.exchange.get_asset('eth_btc')
|
||||||
|
orderbook = self.exchange.get_orderbook(asset, 'all', limit=10)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_get_fees(self):
|
||||||
|
pass
|
||||||
@@ -37,7 +37,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithLogger,
|
WithLogger,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.classproperty import classproperty
|
from catalyst.utils.classproperty import classproperty
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ class BlotterTestCase(WithCreateBarData,
|
|||||||
WithLogger,
|
WithLogger,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-05', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-05', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
||||||
ASSET_FINDER_EQUITY_SIDS = 24, 25
|
ASSET_FINDER_EQUITY_SIDS = 24, 25
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from catalyst.finance.commission import (
|
|||||||
)
|
)
|
||||||
from catalyst.finance.order import Order
|
from catalyst.finance.order import Order
|
||||||
from catalyst.finance.transaction import Transaction
|
from catalyst.finance.transaction import Transaction
|
||||||
from catalyst.testing import ZiplineTestCase, trades_by_sid_to_dfs
|
from catalyst.testing import CatalystTestCase, trades_by_sid_to_dfs
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithAssetFinder,
|
WithAssetFinder,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
@@ -28,7 +28,7 @@ from catalyst.testing.fixtures import (
|
|||||||
from catalyst.utils import factory
|
from catalyst.utils import factory
|
||||||
|
|
||||||
|
|
||||||
class CommissionUnitTests(WithAssetFinder, ZiplineTestCase):
|
class CommissionUnitTests(WithAssetFinder, CatalystTestCase):
|
||||||
ASSET_FINDER_EQUITY_SIDS = 1, 2
|
ASSET_FINDER_EQUITY_SIDS = 1, 2
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -272,7 +272,7 @@ class CommissionUnitTests(WithAssetFinder, ZiplineTestCase):
|
|||||||
self.assertAlmostEqual(15.3, model.calculate(order, txns[2]))
|
self.assertAlmostEqual(15.3, model.calculate(order, txns[2]))
|
||||||
|
|
||||||
|
|
||||||
class CommissionAlgorithmTests(WithDataPortal, WithSimParams, ZiplineTestCase):
|
class CommissionAlgorithmTests(WithDataPortal, WithSimParams, CatalystTestCase):
|
||||||
# make sure order commissions are properly incremented
|
# make sure order commissions are properly incremented
|
||||||
|
|
||||||
sidint, = ASSET_FINDER_EQUITY_SIDS = (133,)
|
sidint, = ASSET_FINDER_EQUITY_SIDS = (133,)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.classproperty import classproperty
|
from catalyst.utils.classproperty import classproperty
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ TestOrder = namedtuple('TestOrder', 'limit direction')
|
|||||||
class SlippageTestCase(WithCreateBarData,
|
class SlippageTestCase(WithCreateBarData,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-05 14:31', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-05 14:31', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-05 14:36', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-05 14:36', tz='utc')
|
||||||
SIM_PARAMS_CAPITAL_BASE = 1.0e5
|
SIM_PARAMS_CAPITAL_BASE = 1.0e5
|
||||||
@@ -566,7 +566,7 @@ class SlippageTestCase(WithCreateBarData,
|
|||||||
class VolumeShareSlippageTestCase(WithCreateBarData,
|
class VolumeShareSlippageTestCase(WithCreateBarData,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
START_DATE = pd.Timestamp('2006-01-05 14:31', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-05 14:31', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-05 14:36', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-05 14:36', tz='utc')
|
||||||
@@ -743,7 +743,7 @@ class VolumeShareSlippageTestCase(WithCreateBarData,
|
|||||||
class VolatilityVolumeShareTestCase(WithCreateBarData,
|
class VolatilityVolumeShareTestCase(WithCreateBarData,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
ASSET_START_DATE = pd.Timestamp('2006-02-10')
|
ASSET_START_DATE = pd.Timestamp('2006-02-10')
|
||||||
|
|
||||||
@@ -890,7 +890,7 @@ class VolatilityVolumeShareTestCase(WithCreateBarData,
|
|||||||
self.assertIsNone(amount)
|
self.assertIsNone(amount)
|
||||||
|
|
||||||
|
|
||||||
class MarketImpactTestCase(WithCreateBarData, ZiplineTestCase):
|
class MarketImpactTestCase(WithCreateBarData, CatalystTestCase):
|
||||||
|
|
||||||
ASSET_FINDER_EQUITY_SIDS = (1,)
|
ASSET_FINDER_EQUITY_SIDS = (1,)
|
||||||
|
|
||||||
@@ -947,7 +947,7 @@ class MarketImpactTestCase(WithCreateBarData, ZiplineTestCase):
|
|||||||
|
|
||||||
class OrdersStopTestCase(WithSimParams,
|
class OrdersStopTestCase(WithSimParams,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
START_DATE = pd.Timestamp('2006-01-05 14:31', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-05 14:31', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-05 14:36', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-05 14:36', tz='utc')
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from catalyst.testing import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithAssetFinder,
|
WithAssetFinder,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
from catalyst.utils.functional import dzip_exact
|
from catalyst.utils.functional import dzip_exact
|
||||||
@@ -54,7 +54,7 @@ with_default_shape = with_defaults(shape=lambda self: self.default_shape)
|
|||||||
|
|
||||||
class BasePipelineTestCase(WithTradingSessions,
|
class BasePipelineTestCase(WithTradingSessions,
|
||||||
WithAssetFinder,
|
WithAssetFinder,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = Timestamp('2014', tz='UTC')
|
START_DATE = Timestamp('2014', tz='UTC')
|
||||||
END_DATE = Timestamp('2014-12-31', tz='UTC')
|
END_DATE = Timestamp('2014-12-31', tz='UTC')
|
||||||
ASSET_FINDER_EQUITY_SIDS = list(range(20))
|
ASSET_FINDER_EQUITY_SIDS = list(range(20))
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from catalyst.pipeline.loaders.blaze.core import (
|
|||||||
NonPipelineField,
|
NonPipelineField,
|
||||||
)
|
)
|
||||||
from catalyst.testing import (
|
from catalyst.testing import (
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
parameter_space,
|
parameter_space,
|
||||||
tmp_asset_finder,
|
tmp_asset_finder,
|
||||||
)
|
)
|
||||||
@@ -77,7 +77,7 @@ def _utc_localize_index_level_0(df):
|
|||||||
return df
|
return df
|
||||||
|
|
||||||
|
|
||||||
class BlazeToPipelineTestCase(WithAssetFinder, ZiplineTestCase):
|
class BlazeToPipelineTestCase(WithAssetFinder, CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp(0)
|
START_DATE = pd.Timestamp(0)
|
||||||
END_DATE = pd.Timestamp('2015')
|
END_DATE = pd.Timestamp('2015')
|
||||||
|
|
||||||
@@ -1927,7 +1927,7 @@ class BlazeToPipelineTestCase(WithAssetFinder, ZiplineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class MiscTestCase(ZiplineTestCase):
|
class MiscTestCase(CatalystTestCase):
|
||||||
def test_exprdata_repr(self):
|
def test_exprdata_repr(self):
|
||||||
strd = set()
|
strd = set()
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import pandas as pd
|
|||||||
from catalyst.lib.labelarray import LabelArray
|
from catalyst.lib.labelarray import LabelArray
|
||||||
from catalyst.pipeline import Classifier
|
from catalyst.pipeline import Classifier
|
||||||
from catalyst.testing import parameter_space
|
from catalyst.testing import parameter_space
|
||||||
from catalyst.testing.fixtures import ZiplineTestCase
|
from catalyst.testing.fixtures import CatalystTestCase
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.utils.numpy_utils import (
|
from catalyst.utils.numpy_utils import (
|
||||||
categorical_dtype,
|
categorical_dtype,
|
||||||
@@ -585,7 +585,7 @@ class ClassifierTestCase(BasePipelineTestCase):
|
|||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
|
||||||
class TestPostProcessAndToWorkSpaceValue(ZiplineTestCase):
|
class TestPostProcessAndToWorkSpaceValue(CatalystTestCase):
|
||||||
def test_reversability_categorical(self):
|
def test_reversability_categorical(self):
|
||||||
class F(Classifier):
|
class F(Classifier):
|
||||||
inputs = ()
|
inputs = ()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from catalyst.pipeline import (
|
|||||||
from catalyst.pipeline.data.testing import TestingDataSet
|
from catalyst.pipeline.data.testing import TestingDataSet
|
||||||
from catalyst.pipeline.factors.equity import SimpleMovingAverage
|
from catalyst.pipeline.factors.equity import SimpleMovingAverage
|
||||||
from catalyst.pipeline.filters.smoothing import All
|
from catalyst.pipeline.filters.smoothing import All
|
||||||
from catalyst.testing import ZiplineTestCase, parameter_space
|
from catalyst.testing import CatalystTestCase, parameter_space
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
WithSeededRandomPipelineEngine,
|
WithSeededRandomPipelineEngine,
|
||||||
@@ -44,7 +44,7 @@ class NDaysAgoClassifier(CustomClassifier):
|
|||||||
out[:] = cats[0]
|
out[:] = cats[0]
|
||||||
|
|
||||||
|
|
||||||
class ComputeExtraRowsTestcase(WithTradingSessions, ZiplineTestCase):
|
class ComputeExtraRowsTestcase(WithTradingSessions, CatalystTestCase):
|
||||||
|
|
||||||
DATA_MIN_DAY = pd.Timestamp('2012-06', tz='UTC')
|
DATA_MIN_DAY = pd.Timestamp('2012-06', tz='UTC')
|
||||||
DATA_MAX_DAY = pd.Timestamp('2015', tz='UTC')
|
DATA_MAX_DAY = pd.Timestamp('2015', tz='UTC')
|
||||||
@@ -555,7 +555,7 @@ class ComputeExtraRowsTestcase(WithTradingSessions, ZiplineTestCase):
|
|||||||
|
|
||||||
|
|
||||||
class DownsampledPipelineTestCase(WithSeededRandomPipelineEngine,
|
class DownsampledPipelineTestCase(WithSeededRandomPipelineEngine,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
# Extend into the last few days of 2013 to test year/quarter boundaries.
|
# Extend into the last few days of 2013 to test year/quarter boundaries.
|
||||||
START_DATE = pd.Timestamp('2013-12-15', tz='UTC')
|
START_DATE = pd.Timestamp('2013-12-15', tz='UTC')
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithEquityPricingPipelineEngine,
|
WithEquityPricingPipelineEngine,
|
||||||
WithSeededRandomPipelineEngine,
|
WithSeededRandomPipelineEngine,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.utils.memoize import lazyval
|
from catalyst.utils.memoize import lazyval
|
||||||
@@ -199,7 +199,7 @@ class WithConstantInputs(WithTradingEnvironment):
|
|||||||
cls.assets = cls.asset_finder.retrieve_all(cls.asset_ids)
|
cls.assets = cls.asset_finder.retrieve_all(cls.asset_ids)
|
||||||
|
|
||||||
|
|
||||||
class ConstantInputTestCase(WithConstantInputs, ZiplineTestCase):
|
class ConstantInputTestCase(WithConstantInputs, CatalystTestCase):
|
||||||
def test_bad_dates(self):
|
def test_bad_dates(self):
|
||||||
loader = self.loader
|
loader = self.loader
|
||||||
engine = SimplePipelineEngine(
|
engine = SimplePipelineEngine(
|
||||||
@@ -816,7 +816,7 @@ class ConstantInputTestCase(WithConstantInputs, ZiplineTestCase):
|
|||||||
Loader2DataSet.col2)})
|
Loader2DataSet.col2)})
|
||||||
|
|
||||||
|
|
||||||
class FrameInputTestCase(WithTradingEnvironment, ZiplineTestCase):
|
class FrameInputTestCase(WithTradingEnvironment, CatalystTestCase):
|
||||||
asset_ids = ASSET_FINDER_EQUITY_SIDS = 1, 2, 3
|
asset_ids = ASSET_FINDER_EQUITY_SIDS = 1, 2, 3
|
||||||
start = START_DATE = Timestamp('2015-01-01', tz='utc')
|
start = START_DATE = Timestamp('2015-01-01', tz='utc')
|
||||||
end = END_DATE = Timestamp('2015-01-31', tz='utc')
|
end = END_DATE = Timestamp('2015-01-31', tz='utc')
|
||||||
@@ -921,7 +921,7 @@ class FrameInputTestCase(WithTradingEnvironment, ZiplineTestCase):
|
|||||||
|
|
||||||
|
|
||||||
class SyntheticBcolzTestCase(WithAdjustmentReader,
|
class SyntheticBcolzTestCase(WithAdjustmentReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
first_asset_start = Timestamp('2015-04-01', tz='UTC')
|
first_asset_start = Timestamp('2015-04-01', tz='UTC')
|
||||||
START_DATE = Timestamp('2015-01-01', tz='utc')
|
START_DATE = Timestamp('2015-01-01', tz='utc')
|
||||||
END_DATE = Timestamp('2015-08-01', tz='utc')
|
END_DATE = Timestamp('2015-08-01', tz='utc')
|
||||||
@@ -1079,7 +1079,7 @@ class SyntheticBcolzTestCase(WithAdjustmentReader,
|
|||||||
assert_frame_equal(expected, result)
|
assert_frame_equal(expected, result)
|
||||||
|
|
||||||
|
|
||||||
class ParameterizedFactorTestCase(WithTradingEnvironment, ZiplineTestCase):
|
class ParameterizedFactorTestCase(WithTradingEnvironment, CatalystTestCase):
|
||||||
sids = ASSET_FINDER_EQUITY_SIDS = Int64Index([1, 2, 3])
|
sids = ASSET_FINDER_EQUITY_SIDS = Int64Index([1, 2, 3])
|
||||||
START_DATE = Timestamp('2015-01-31', tz='UTC')
|
START_DATE = Timestamp('2015-01-31', tz='UTC')
|
||||||
END_DATE = Timestamp('2015-03-01', tz='UTC')
|
END_DATE = Timestamp('2015-03-01', tz='UTC')
|
||||||
@@ -1297,7 +1297,7 @@ class ParameterizedFactorTestCase(WithTradingEnvironment, ZiplineTestCase):
|
|||||||
|
|
||||||
|
|
||||||
class StringColumnTestCase(WithSeededRandomPipelineEngine,
|
class StringColumnTestCase(WithSeededRandomPipelineEngine,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
def test_string_classifiers_produce_categoricals(self):
|
def test_string_classifiers_produce_categoricals(self):
|
||||||
"""
|
"""
|
||||||
@@ -1327,7 +1327,7 @@ class StringColumnTestCase(WithSeededRandomPipelineEngine,
|
|||||||
|
|
||||||
|
|
||||||
class WindowSafetyPropagationTestCase(WithSeededRandomPipelineEngine,
|
class WindowSafetyPropagationTestCase(WithSeededRandomPipelineEngine,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
SEEDED_RANDOM_PIPELINE_SEED = 5
|
SEEDED_RANDOM_PIPELINE_SEED = 5
|
||||||
|
|
||||||
@@ -1378,7 +1378,7 @@ class WindowSafetyPropagationTestCase(WithSeededRandomPipelineEngine,
|
|||||||
assert_equal(expected_result, results[colname])
|
assert_equal(expected_result, results[colname])
|
||||||
|
|
||||||
|
|
||||||
class PopulateInitialWorkspaceTestCase(WithConstantInputs, ZiplineTestCase):
|
class PopulateInitialWorkspaceTestCase(WithConstantInputs, CatalystTestCase):
|
||||||
|
|
||||||
@parameter_space(window_length=[3, 5], pipeline_length=[5, 10])
|
@parameter_space(window_length=[3, 5], pipeline_length=[5, 10])
|
||||||
def test_populate_initial_workspace(self, window_length, pipeline_length):
|
def test_populate_initial_workspace(self, window_length, pipeline_length):
|
||||||
@@ -1503,7 +1503,7 @@ class PopulateInitialWorkspaceTestCase(WithConstantInputs, ZiplineTestCase):
|
|||||||
|
|
||||||
|
|
||||||
class ChunkedPipelineTestCase(WithEquityPricingPipelineEngine,
|
class ChunkedPipelineTestCase(WithEquityPricingPipelineEngine,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
PIPELINE_START_DATE = Timestamp('2006-01-05', tz='UTC')
|
PIPELINE_START_DATE = Timestamp('2006-01-05', tz='UTC')
|
||||||
END_DATE = Timestamp('2006-12-29', tz='UTC')
|
END_DATE = Timestamp('2006-12-29', tz='UTC')
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ from catalyst.pipeline.loaders.utils import (
|
|||||||
normalize_timestamp_to_query_time,
|
normalize_timestamp_to_query_time,
|
||||||
previous_event_indexer,
|
previous_event_indexer,
|
||||||
)
|
)
|
||||||
from catalyst.testing import check_arrays, ZiplineTestCase
|
from catalyst.testing import check_arrays, CatalystTestCase
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithAssetFinder,
|
WithAssetFinder,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
@@ -148,7 +148,7 @@ def make_events(add_nulls):
|
|||||||
return pd.concat(event_frames, ignore_index=True)
|
return pd.concat(event_frames, ignore_index=True)
|
||||||
|
|
||||||
|
|
||||||
class EventIndexerTestCase(ZiplineTestCase):
|
class EventIndexerTestCase(CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def init_class_fixtures(cls):
|
def init_class_fixtures(cls):
|
||||||
@@ -269,7 +269,7 @@ class EventIndexerTestCase(ZiplineTestCase):
|
|||||||
|
|
||||||
class EventsLoaderEmptyTestCase(WithAssetFinder,
|
class EventsLoaderEmptyTestCase(WithAssetFinder,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2014-01-01')
|
START_DATE = pd.Timestamp('2014-01-01')
|
||||||
END_DATE = pd.Timestamp('2014-01-30')
|
END_DATE = pd.Timestamp('2014-01-30')
|
||||||
|
|
||||||
@@ -351,7 +351,7 @@ class EventsLoaderEmptyTestCase(WithAssetFinder,
|
|||||||
|
|
||||||
class EventsLoaderTestCase(WithAssetFinder,
|
class EventsLoaderTestCase(WithAssetFinder,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
START_DATE = pd.Timestamp('2014-01-01')
|
START_DATE = pd.Timestamp('2014-01-01')
|
||||||
END_DATE = pd.Timestamp('2014-01-30')
|
END_DATE = pd.Timestamp('2014-01-30')
|
||||||
@@ -586,7 +586,7 @@ class BlazeEventsLoaderTestCase(EventsLoaderTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class EventLoaderUtilsTestCase(ZiplineTestCase):
|
class EventLoaderUtilsTestCase(CatalystTestCase):
|
||||||
# These cases test the following:
|
# These cases test the following:
|
||||||
# 1. Shuffling timestamps in DST/EST produces the correct normalized
|
# 1. Shuffling timestamps in DST/EST produces the correct normalized
|
||||||
# timestamps
|
# timestamps
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ from catalyst.testing import (
|
|||||||
parameter_space,
|
parameter_space,
|
||||||
permute_rows,
|
permute_rows,
|
||||||
)
|
)
|
||||||
from catalyst.testing.fixtures import ZiplineTestCase
|
from catalyst.testing.fixtures import CatalystTestCase
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.utils.numpy_utils import (
|
from catalyst.utils.numpy_utils import (
|
||||||
categorical_dtype,
|
categorical_dtype,
|
||||||
@@ -1246,7 +1246,7 @@ class TestWindowSafety(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestPostProcessAndToWorkSpaceValue(ZiplineTestCase):
|
class TestPostProcessAndToWorkSpaceValue(CatalystTestCase):
|
||||||
@parameter_space(dtype_=(float64_dtype, datetime64ns_dtype))
|
@parameter_space(dtype_=(float64_dtype, datetime64ns_dtype))
|
||||||
def test_reversability(self, dtype_):
|
def test_reversability(self, dtype_):
|
||||||
class F(Factor):
|
class F(Factor):
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ from catalyst.pipeline.filters import (
|
|||||||
StaticAssets,
|
StaticAssets,
|
||||||
StaticSids,
|
StaticSids,
|
||||||
)
|
)
|
||||||
from catalyst.testing import parameter_space, permute_rows, ZiplineTestCase
|
from catalyst.testing import parameter_space, permute_rows, CatalystTestCase
|
||||||
from catalyst.testing.fixtures import WithSeededRandomPipelineEngine
|
from catalyst.testing.fixtures import WithSeededRandomPipelineEngine
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.utils.numpy_utils import float64_dtype, int64_dtype
|
from catalyst.utils.numpy_utils import float64_dtype, int64_dtype
|
||||||
@@ -841,7 +841,7 @@ class SidFactor(CustomFactor):
|
|||||||
|
|
||||||
|
|
||||||
class SpecificAssetsTestCase(WithSeededRandomPipelineEngine,
|
class SpecificAssetsTestCase(WithSeededRandomPipelineEngine,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
ASSET_FINDER_EQUITY_SIDS = tuple(range(10))
|
ASSET_FINDER_EQUITY_SIDS = tuple(range(10))
|
||||||
|
|
||||||
@@ -887,7 +887,7 @@ class SpecificAssetsTestCase(WithSeededRandomPipelineEngine,
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestPostProcessAndToWorkSpaceValue(ZiplineTestCase):
|
class TestPostProcessAndToWorkSpaceValue(CatalystTestCase):
|
||||||
def test_reversability(self):
|
def test_reversability(self):
|
||||||
class F(Filter):
|
class F(Filter):
|
||||||
inputs = ()
|
inputs = ()
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithAdjustmentReader,
|
WithAdjustmentReader,
|
||||||
WithBcolzEquityDailyBarReaderFromCSVs,
|
WithBcolzEquityDailyBarReaderFromCSVs,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.calendars import get_calendar
|
from catalyst.utils.calendars import get_calendar
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ def rolling_vwap(df, length):
|
|||||||
return Series(out, index=df.index)
|
return Series(out, index=df.index)
|
||||||
|
|
||||||
|
|
||||||
class ClosesOnly(WithDataPortal, ZiplineTestCase):
|
class ClosesOnly(WithDataPortal, CatalystTestCase):
|
||||||
sids = 1, 2, 3
|
sids = 1, 2, 3
|
||||||
START_DATE = pd.Timestamp('2014-01-01', tz='utc')
|
START_DATE = pd.Timestamp('2014-01-01', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2014-02-01', tz='utc')
|
END_DATE = pd.Timestamp('2014-02-01', tz='utc')
|
||||||
@@ -355,7 +355,7 @@ class MockDailyBarSpotReader(object):
|
|||||||
|
|
||||||
class PipelineAlgorithmTestCase(WithBcolzEquityDailyBarReaderFromCSVs,
|
class PipelineAlgorithmTestCase(WithBcolzEquityDailyBarReaderFromCSVs,
|
||||||
WithAdjustmentReader,
|
WithAdjustmentReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
AAPL = 1
|
AAPL = 1
|
||||||
MSFT = 2
|
MSFT = 2
|
||||||
BRK_A = 3
|
BRK_A = 3
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ from catalyst.pipeline.loaders.earnings_estimates import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithAdjustmentReader,
|
WithAdjustmentReader,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.testing.predicates import assert_equal, assert_raises_regex
|
from catalyst.testing.predicates import assert_equal, assert_raises_regex
|
||||||
from catalyst.testing.predicates import assert_frame_equal
|
from catalyst.testing.predicates import assert_frame_equal
|
||||||
@@ -113,7 +113,7 @@ def create_expected_df_for_factor_compute(start_date,
|
|||||||
|
|
||||||
class WithEstimates(WithTradingSessions, WithAdjustmentReader):
|
class WithEstimates(WithTradingSessions, WithAdjustmentReader):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.loader and cls.events as class
|
CatalystTestCase mixin providing cls.loader and cls.events as class
|
||||||
level fixtures.
|
level fixtures.
|
||||||
|
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ class WithEstimates(WithTradingSessions, WithAdjustmentReader):
|
|||||||
|
|
||||||
class WithOneDayPipeline(WithEstimates):
|
class WithOneDayPipeline(WithEstimates):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.events as a class level fixture and
|
CatalystTestCase mixin providing cls.events as a class level fixture and
|
||||||
defining a test for all inheritors to use.
|
defining a test for all inheritors to use.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
@@ -246,7 +246,7 @@ class WithOneDayPipeline(WithEstimates):
|
|||||||
assert_frame_equal(results, self.expected_out)
|
assert_frame_equal(results, self.expected_out)
|
||||||
|
|
||||||
|
|
||||||
class PreviousWithOneDayPipeline(WithOneDayPipeline, ZiplineTestCase):
|
class PreviousWithOneDayPipeline(WithOneDayPipeline, CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Tests that previous quarter loader correctly breaks if an incorrect
|
Tests that previous quarter loader correctly breaks if an incorrect
|
||||||
number of quarters is passed.
|
number of quarters is passed.
|
||||||
@@ -271,7 +271,7 @@ class PreviousWithOneDayPipeline(WithOneDayPipeline, ZiplineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class NextWithOneDayPipeline(WithOneDayPipeline, ZiplineTestCase):
|
class NextWithOneDayPipeline(WithOneDayPipeline, CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Tests that next quarter loader correctly breaks if an incorrect
|
Tests that next quarter loader correctly breaks if an incorrect
|
||||||
number of quarters is passed.
|
number of quarters is passed.
|
||||||
@@ -308,7 +308,7 @@ dummy_df = pd.DataFrame({SID_FIELD_NAME: 0},
|
|||||||
|
|
||||||
class WithWrongLoaderDefinition(WithEstimates):
|
class WithWrongLoaderDefinition(WithEstimates):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.events as a class level fixture and
|
CatalystTestCase mixin providing cls.events as a class level fixture and
|
||||||
defining a test for all inheritors to use.
|
defining a test for all inheritors to use.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
@@ -372,7 +372,7 @@ class WithWrongLoaderDefinition(WithEstimates):
|
|||||||
|
|
||||||
|
|
||||||
class PreviousWithWrongNumQuarters(WithWrongLoaderDefinition,
|
class PreviousWithWrongNumQuarters(WithWrongLoaderDefinition,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Tests that previous quarter loader correctly breaks if an incorrect
|
Tests that previous quarter loader correctly breaks if an incorrect
|
||||||
number of quarters is passed.
|
number of quarters is passed.
|
||||||
@@ -383,7 +383,7 @@ class PreviousWithWrongNumQuarters(WithWrongLoaderDefinition,
|
|||||||
|
|
||||||
|
|
||||||
class NextWithWrongNumQuarters(WithWrongLoaderDefinition,
|
class NextWithWrongNumQuarters(WithWrongLoaderDefinition,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Tests that next quarter loader correctly breaks if an incorrect
|
Tests that next quarter loader correctly breaks if an incorrect
|
||||||
number of quarters is passed.
|
number of quarters is passed.
|
||||||
@@ -398,7 +398,7 @@ options = ["split_adjustments_loader",
|
|||||||
"split_adjusted_asof"]
|
"split_adjusted_asof"]
|
||||||
|
|
||||||
|
|
||||||
class WrongSplitsLoaderDefinition(WithEstimates, ZiplineTestCase):
|
class WrongSplitsLoaderDefinition(WithEstimates, CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Test class that tests that loaders break correctly when incorrectly
|
Test class that tests that loaders break correctly when incorrectly
|
||||||
instantiated.
|
instantiated.
|
||||||
@@ -436,7 +436,7 @@ class WrongSplitsLoaderDefinition(WithEstimates, ZiplineTestCase):
|
|||||||
|
|
||||||
class WithEstimatesTimeZero(WithEstimates):
|
class WithEstimatesTimeZero(WithEstimates):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.events as a class level fixture and
|
CatalystTestCase mixin providing cls.events as a class level fixture and
|
||||||
defining a test for all inheritors to use.
|
defining a test for all inheritors to use.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
@@ -622,7 +622,7 @@ class WithEstimatesTimeZero(WithEstimates):
|
|||||||
sid_estimates)
|
sid_estimates)
|
||||||
|
|
||||||
|
|
||||||
class NextEstimate(WithEstimatesTimeZero, ZiplineTestCase):
|
class NextEstimate(WithEstimatesTimeZero, CatalystTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
return NextEarningsEstimatesLoader(events, columns)
|
return NextEarningsEstimatesLoader(events, columns)
|
||||||
@@ -662,7 +662,7 @@ class BlazeNextEstimateLoaderTestCase(NextEstimate):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PreviousEstimate(WithEstimatesTimeZero, ZiplineTestCase):
|
class PreviousEstimate(WithEstimatesTimeZero, CatalystTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
return PreviousEarningsEstimatesLoader(events, columns)
|
return PreviousEarningsEstimatesLoader(events, columns)
|
||||||
@@ -703,7 +703,7 @@ class BlazePreviousEstimateLoaderTestCase(PreviousEstimate):
|
|||||||
|
|
||||||
class WithEstimateMultipleQuarters(WithEstimates):
|
class WithEstimateMultipleQuarters(WithEstimates):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing cls.events, cls.make_expected_out as
|
CatalystTestCase mixin providing cls.events, cls.make_expected_out as
|
||||||
class-level fixtures and self.test_multiple_qtrs_requested as a test.
|
class-level fixtures and self.test_multiple_qtrs_requested as a test.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
@@ -797,7 +797,7 @@ class WithEstimateMultipleQuarters(WithEstimates):
|
|||||||
|
|
||||||
|
|
||||||
class NextEstimateMultipleQuarters(
|
class NextEstimateMultipleQuarters(
|
||||||
WithEstimateMultipleQuarters, ZiplineTestCase
|
WithEstimateMultipleQuarters, CatalystTestCase
|
||||||
):
|
):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
@@ -854,7 +854,7 @@ class BlazeNextEstimateMultipleQuarters(NextEstimateMultipleQuarters):
|
|||||||
|
|
||||||
class PreviousEstimateMultipleQuarters(
|
class PreviousEstimateMultipleQuarters(
|
||||||
WithEstimateMultipleQuarters,
|
WithEstimateMultipleQuarters,
|
||||||
ZiplineTestCase
|
CatalystTestCase
|
||||||
):
|
):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -903,7 +903,7 @@ class BlazePreviousEstimateMultipleQuarters(PreviousEstimateMultipleQuarters):
|
|||||||
|
|
||||||
class WithVaryingNumEstimates(WithEstimates):
|
class WithVaryingNumEstimates(WithEstimates):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing fixtures and a test to ensure that we
|
CatalystTestCase mixin providing fixtures and a test to ensure that we
|
||||||
have the correct overwrites when the event date changes. We want to make
|
have the correct overwrites when the event date changes. We want to make
|
||||||
sure that if we have a quarter with an event date that gets pushed back,
|
sure that if we have a quarter with an event date that gets pushed back,
|
||||||
we don't start overwriting for the next quarter early. Likewise,
|
we don't start overwriting for the next quarter early. Likewise,
|
||||||
@@ -973,7 +973,7 @@ class WithVaryingNumEstimates(WithEstimates):
|
|||||||
|
|
||||||
class PreviousVaryingNumEstimates(
|
class PreviousVaryingNumEstimates(
|
||||||
WithVaryingNumEstimates,
|
WithVaryingNumEstimates,
|
||||||
ZiplineTestCase
|
CatalystTestCase
|
||||||
):
|
):
|
||||||
def assert_compute(self, estimate, today):
|
def assert_compute(self, estimate, today):
|
||||||
if today == pd.Timestamp('2015-01-13', tz='utc'):
|
if today == pd.Timestamp('2015-01-13', tz='utc'):
|
||||||
@@ -1003,7 +1003,7 @@ class BlazePreviousVaryingNumEstimates(PreviousVaryingNumEstimates):
|
|||||||
|
|
||||||
class NextVaryingNumEstimates(
|
class NextVaryingNumEstimates(
|
||||||
WithVaryingNumEstimates,
|
WithVaryingNumEstimates,
|
||||||
ZiplineTestCase
|
CatalystTestCase
|
||||||
):
|
):
|
||||||
|
|
||||||
def assert_compute(self, estimate, today):
|
def assert_compute(self, estimate, today):
|
||||||
@@ -1034,7 +1034,7 @@ class BlazeNextVaryingNumEstimates(NextVaryingNumEstimates):
|
|||||||
|
|
||||||
class WithEstimateWindows(WithEstimates):
|
class WithEstimateWindows(WithEstimates):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing fixures and a test to test running a
|
CatalystTestCase mixin providing fixures and a test to test running a
|
||||||
Pipeline with an estimates loader over differently-sized windows.
|
Pipeline with an estimates loader over differently-sized windows.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
@@ -1198,7 +1198,7 @@ class WithEstimateWindows(WithEstimates):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PreviousEstimateWindows(WithEstimateWindows, ZiplineTestCase):
|
class PreviousEstimateWindows(WithEstimateWindows, CatalystTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
return PreviousEarningsEstimatesLoader(events, columns)
|
return PreviousEarningsEstimatesLoader(events, columns)
|
||||||
@@ -1279,7 +1279,7 @@ class BlazePreviousEstimateWindows(PreviousEstimateWindows):
|
|||||||
return BlazePreviousEstimatesLoader(bz.data(events), columns)
|
return BlazePreviousEstimatesLoader(bz.data(events), columns)
|
||||||
|
|
||||||
|
|
||||||
class NextEstimateWindows(WithEstimateWindows, ZiplineTestCase):
|
class NextEstimateWindows(WithEstimateWindows, CatalystTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
return NextEarningsEstimatesLoader(events, columns)
|
return NextEarningsEstimatesLoader(events, columns)
|
||||||
@@ -1394,7 +1394,7 @@ class BlazeNextEstimateWindows(NextEstimateWindows):
|
|||||||
|
|
||||||
class WithSplitAdjustedWindows(WithEstimateWindows):
|
class WithSplitAdjustedWindows(WithEstimateWindows):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing fixures and a test to test running a
|
CatalystTestCase mixin providing fixures and a test to test running a
|
||||||
Pipeline with an estimates loader over differently-sized windows and with
|
Pipeline with an estimates loader over differently-sized windows and with
|
||||||
split adjustments.
|
split adjustments.
|
||||||
"""
|
"""
|
||||||
@@ -1572,7 +1572,7 @@ class WithSplitAdjustedWindows(WithEstimateWindows):
|
|||||||
|
|
||||||
|
|
||||||
class PreviousWithSplitAdjustedWindows(WithSplitAdjustedWindows,
|
class PreviousWithSplitAdjustedWindows(WithSplitAdjustedWindows,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
return PreviousSplitAdjustedEarningsEstimatesLoader(
|
return PreviousSplitAdjustedEarningsEstimatesLoader(
|
||||||
@@ -1726,7 +1726,7 @@ class BlazePreviousWithSplitAdjustedWindows(PreviousWithSplitAdjustedWindows):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class NextWithSplitAdjustedWindows(WithSplitAdjustedWindows, ZiplineTestCase):
|
class NextWithSplitAdjustedWindows(WithSplitAdjustedWindows, CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
@@ -1951,7 +1951,7 @@ class BlazeNextWithSplitAdjustedWindows(NextWithSplitAdjustedWindows):
|
|||||||
|
|
||||||
class WithSplitAdjustedMultipleEstimateColumns(WithEstimates):
|
class WithSplitAdjustedMultipleEstimateColumns(WithEstimates):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin for having multiple estimate columns that are
|
CatalystTestCase mixin for having multiple estimate columns that are
|
||||||
split-adjusted to make sure that adjustments are applied correctly.
|
split-adjusted to make sure that adjustments are applied correctly.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
@@ -2136,7 +2136,7 @@ class WithSplitAdjustedMultipleEstimateColumns(WithEstimates):
|
|||||||
|
|
||||||
|
|
||||||
class PreviousWithSplitAdjustedMultipleEstimateColumns(
|
class PreviousWithSplitAdjustedMultipleEstimateColumns(
|
||||||
WithSplitAdjustedMultipleEstimateColumns, ZiplineTestCase
|
WithSplitAdjustedMultipleEstimateColumns, CatalystTestCase
|
||||||
):
|
):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
@@ -2218,7 +2218,7 @@ class BlazePreviousWithMultipleEstimateColumns(
|
|||||||
|
|
||||||
|
|
||||||
class NextWithSplitAdjustedMultipleEstimateColumns(
|
class NextWithSplitAdjustedMultipleEstimateColumns(
|
||||||
WithSplitAdjustedMultipleEstimateColumns, ZiplineTestCase
|
WithSplitAdjustedMultipleEstimateColumns, CatalystTestCase
|
||||||
):
|
):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
@@ -2295,7 +2295,7 @@ class BlazeNextWithMultipleEstimateColumns(
|
|||||||
|
|
||||||
class WithAdjustmentBoundaries(WithEstimates):
|
class WithAdjustmentBoundaries(WithEstimates):
|
||||||
"""
|
"""
|
||||||
ZiplineTestCase mixin providing class-level attributes, methods,
|
CatalystTestCase mixin providing class-level attributes, methods,
|
||||||
and a test to make sure that when the split-adjusted-asof-date is not
|
and a test to make sure that when the split-adjusted-asof-date is not
|
||||||
strictly within the date index, we can still apply adjustments correctly.
|
strictly within the date index, we can still apply adjustments correctly.
|
||||||
|
|
||||||
@@ -2470,7 +2470,7 @@ class WithAdjustmentBoundaries(WithEstimates):
|
|||||||
|
|
||||||
|
|
||||||
class PreviousWithAdjustmentBoundaries(WithAdjustmentBoundaries,
|
class PreviousWithAdjustmentBoundaries(WithAdjustmentBoundaries,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
return partial(PreviousSplitAdjustedEarningsEstimatesLoader,
|
return partial(PreviousSplitAdjustedEarningsEstimatesLoader,
|
||||||
@@ -2612,7 +2612,7 @@ class BlazePreviousWithAdjustmentBoundaries(PreviousWithAdjustmentBoundaries):
|
|||||||
|
|
||||||
|
|
||||||
class NextWithAdjustmentBoundaries(WithAdjustmentBoundaries,
|
class NextWithAdjustmentBoundaries(WithAdjustmentBoundaries,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_loader(cls, events, columns):
|
def make_loader(cls, events, columns):
|
||||||
return partial(NextSplitAdjustedEarningsEstimatesLoader,
|
return partial(NextSplitAdjustedEarningsEstimatesLoader,
|
||||||
@@ -2720,7 +2720,7 @@ class BlazeNextWithAdjustmentBoundaries(NextWithAdjustmentBoundaries):
|
|||||||
split_adjusted_column_names=['estimate'])
|
split_adjusted_column_names=['estimate'])
|
||||||
|
|
||||||
|
|
||||||
class QuarterShiftTestCase(ZiplineTestCase):
|
class QuarterShiftTestCase(CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
This tests, in isolation, quarter calculation logic for shifting quarters
|
This tests, in isolation, quarter calculation logic for shifting quarters
|
||||||
backwards/forwards from a starting point.
|
backwards/forwards from a starting point.
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ from catalyst.testing import (
|
|||||||
)
|
)
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithSeededRandomPipelineEngine,
|
WithSeededRandomPipelineEngine,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.numpy_utils import datetime64ns_dtype
|
from catalyst.utils.numpy_utils import datetime64ns_dtype
|
||||||
|
|
||||||
|
|
||||||
class SliceTestCase(WithSeededRandomPipelineEngine, ZiplineTestCase):
|
class SliceTestCase(WithSeededRandomPipelineEngine, CatalystTestCase):
|
||||||
sids = ASSET_FINDER_EQUITY_SIDS = Int64Index([1, 2, 3])
|
sids = ASSET_FINDER_EQUITY_SIDS = Int64Index([1, 2, 3])
|
||||||
START_DATE = Timestamp('2015-01-31', tz='UTC')
|
START_DATE = Timestamp('2015-01-31', tz='UTC')
|
||||||
END_DATE = Timestamp('2015-03-01', tz='UTC')
|
END_DATE = Timestamp('2015-03-01', tz='UTC')
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ from catalyst.testing import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithSeededRandomPipelineEngine,
|
WithSeededRandomPipelineEngine,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.numpy_utils import (
|
from catalyst.utils.numpy_utils import (
|
||||||
bool_dtype,
|
bool_dtype,
|
||||||
@@ -51,7 +51,7 @@ from catalyst.utils.numpy_utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class StatisticalBuiltInsTestCase(WithTradingEnvironment, ZiplineTestCase):
|
class StatisticalBuiltInsTestCase(WithTradingEnvironment, CatalystTestCase):
|
||||||
sids = ASSET_FINDER_EQUITY_SIDS = Int64Index([1, 2, 3])
|
sids = ASSET_FINDER_EQUITY_SIDS = Int64Index([1, 2, 3])
|
||||||
START_DATE = Timestamp('2015-01-31', tz='UTC')
|
START_DATE = Timestamp('2015-01-31', tz='UTC')
|
||||||
END_DATE = Timestamp('2015-03-01', tz='UTC')
|
END_DATE = Timestamp('2015-03-01', tz='UTC')
|
||||||
@@ -388,7 +388,7 @@ class StatisticalBuiltInsTestCase(WithTradingEnvironment, ZiplineTestCase):
|
|||||||
|
|
||||||
|
|
||||||
class StatisticalMethodsTestCase(WithSeededRandomPipelineEngine,
|
class StatisticalMethodsTestCase(WithSeededRandomPipelineEngine,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
sids = ASSET_FINDER_EQUITY_SIDS = Int64Index([1, 2, 3])
|
sids = ASSET_FINDER_EQUITY_SIDS = Int64Index([1, 2, 3])
|
||||||
START_DATE = Timestamp('2015-01-31', tz='UTC')
|
START_DATE = Timestamp('2015-01-31', tz='UTC')
|
||||||
END_DATE = Timestamp('2015-03-01', tz='UTC')
|
END_DATE = Timestamp('2015-03-01', tz='UTC')
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from catalyst.pipeline.factors.equity import (
|
|||||||
AnnualizedVolatility,
|
AnnualizedVolatility,
|
||||||
)
|
)
|
||||||
from catalyst.testing import parameter_space
|
from catalyst.testing import parameter_space
|
||||||
from catalyst.testing.fixtures import ZiplineTestCase
|
from catalyst.testing.fixtures import CatalystTestCase
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from .base import BasePipelineTestCase
|
from .base import BasePipelineTestCase
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class BollingerBandsTestCase(BasePipelineTestCase):
|
|||||||
self.assertIs(upper, bbands.upper)
|
self.assertIs(upper, bbands.upper)
|
||||||
|
|
||||||
|
|
||||||
class AroonTestCase(ZiplineTestCase):
|
class AroonTestCase(CatalystTestCase):
|
||||||
window_length = 10
|
window_length = 10
|
||||||
nassets = 5
|
nassets = 5
|
||||||
dtype = [('down', 'f8'), ('up', 'f8')]
|
dtype = [('down', 'f8'), ('up', 'f8')]
|
||||||
@@ -148,7 +148,7 @@ class AroonTestCase(ZiplineTestCase):
|
|||||||
assert_equal(out, expected_out)
|
assert_equal(out, expected_out)
|
||||||
|
|
||||||
|
|
||||||
class TestFastStochasticOscillator(ZiplineTestCase):
|
class TestFastStochasticOscillator(CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Test the Fast Stochastic Oscillator
|
Test the Fast Stochastic Oscillator
|
||||||
"""
|
"""
|
||||||
@@ -218,7 +218,7 @@ class TestFastStochasticOscillator(ZiplineTestCase):
|
|||||||
assert_equal(out, expected_out_k, array_decimal=6)
|
assert_equal(out, expected_out_k, array_decimal=6)
|
||||||
|
|
||||||
|
|
||||||
class IchimokuKinkoHyoTestCase(ZiplineTestCase):
|
class IchimokuKinkoHyoTestCase(CatalystTestCase):
|
||||||
def test_ichimoku_kinko_hyo(self):
|
def test_ichimoku_kinko_hyo(self):
|
||||||
window_length = 52
|
window_length = 52
|
||||||
today = pd.Timestamp('2014', tz='utc')
|
today = pd.Timestamp('2014', tz='utc')
|
||||||
@@ -334,7 +334,7 @@ class IchimokuKinkoHyoTestCase(ZiplineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestRateOfChangePercentage(ZiplineTestCase):
|
class TestRateOfChangePercentage(CatalystTestCase):
|
||||||
@parameterized.expand([
|
@parameterized.expand([
|
||||||
('constant', [2.] * 10, 0.0),
|
('constant', [2.] * 10, 0.0),
|
||||||
('step', [2.] + [1.] * 9, -50.0),
|
('step', [2.] + [1.] * 9, -50.0),
|
||||||
@@ -358,7 +358,7 @@ class TestRateOfChangePercentage(ZiplineTestCase):
|
|||||||
assert_equal(out, np.full((len(assets),), expected))
|
assert_equal(out, np.full((len(assets),), expected))
|
||||||
|
|
||||||
|
|
||||||
class TestLinearWeightedMovingAverage(ZiplineTestCase):
|
class TestLinearWeightedMovingAverage(CatalystTestCase):
|
||||||
def test_wma1(self):
|
def test_wma1(self):
|
||||||
wma1 = LinearWeightedMovingAverage(
|
wma1 = LinearWeightedMovingAverage(
|
||||||
inputs=(USEquityPricing.close,),
|
inputs=(USEquityPricing.close,),
|
||||||
@@ -390,7 +390,7 @@ class TestLinearWeightedMovingAverage(ZiplineTestCase):
|
|||||||
assert_equal(out, np.array([30., 31., 32., 33., 34.]))
|
assert_equal(out, np.array([30., 31., 32., 33., 34.]))
|
||||||
|
|
||||||
|
|
||||||
class TestTrueRange(ZiplineTestCase):
|
class TestTrueRange(CatalystTestCase):
|
||||||
|
|
||||||
def test_tr_basic(self):
|
def test_tr_basic(self):
|
||||||
tr = TrueRange()
|
tr = TrueRange()
|
||||||
@@ -407,7 +407,7 @@ class TestTrueRange(ZiplineTestCase):
|
|||||||
assert_equal(out, np.full((3,), 2.))
|
assert_equal(out, np.full((3,), 2.))
|
||||||
|
|
||||||
|
|
||||||
class MovingAverageConvergenceDivergenceTestCase(ZiplineTestCase):
|
class MovingAverageConvergenceDivergenceTestCase(CatalystTestCase):
|
||||||
|
|
||||||
def expected_ewma(self, data_df, window):
|
def expected_ewma(self, data_df, window):
|
||||||
# Comment copied from `test_engine.py`:
|
# Comment copied from `test_engine.py`:
|
||||||
@@ -532,7 +532,7 @@ class MovingAverageConvergenceDivergenceTestCase(ZiplineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class AnnualizedVolatilityTestCase(ZiplineTestCase):
|
class AnnualizedVolatilityTestCase(CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Test Annualized Volatility
|
Test Annualized Volatility
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from catalyst.pipeline.factors import RecarrayField
|
|||||||
from catalyst.pipeline.sentinels import NotSpecified
|
from catalyst.pipeline.sentinels import NotSpecified
|
||||||
from catalyst.pipeline.term import AssetExists, Slice
|
from catalyst.pipeline.term import AssetExists, Slice
|
||||||
from catalyst.testing import parameter_space
|
from catalyst.testing import parameter_space
|
||||||
from catalyst.testing.fixtures import WithTradingSessions, ZiplineTestCase
|
from catalyst.testing.fixtures import WithTradingSessions, CatalystTestCase
|
||||||
from catalyst.testing.predicates import (
|
from catalyst.testing.predicates import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
assert_raises,
|
assert_raises,
|
||||||
@@ -155,7 +155,7 @@ def to_dict(l):
|
|||||||
return dict(zip(map(str, range(len(l))), l))
|
return dict(zip(map(str, range(len(l))), l))
|
||||||
|
|
||||||
|
|
||||||
class DependencyResolutionTestCase(WithTradingSessions, ZiplineTestCase):
|
class DependencyResolutionTestCase(WithTradingSessions, CatalystTestCase):
|
||||||
|
|
||||||
TRADING_CALENDAR_STRS = ('NYSE',)
|
TRADING_CALENDAR_STRS = ('NYSE',)
|
||||||
START_DATE = pd.Timestamp('2014-01-02', tz='UTC')
|
START_DATE = pd.Timestamp('2014-01-02', tz='UTC')
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ from catalyst.testing import (
|
|||||||
)
|
)
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithAdjustmentReader,
|
WithAdjustmentReader,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test calendar ranges over the month of June 2015
|
# Test calendar ranges over the month of June 2015
|
||||||
@@ -258,7 +258,7 @@ DIVIDENDS_EXPECTED = DataFrame(
|
|||||||
|
|
||||||
|
|
||||||
class USEquityPricingLoaderTestCase(WithAdjustmentReader,
|
class USEquityPricingLoaderTestCase(WithAdjustmentReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = TEST_CALENDAR_START
|
START_DATE = TEST_CALENDAR_START
|
||||||
END_DATE = TEST_CALENDAR_STOP
|
END_DATE = TEST_CALENDAR_STOP
|
||||||
asset_ids = 1, 2, 3
|
asset_ids = 1, 2, 3
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import pandas as pd
|
|||||||
import catalyst.finance.risk as risk
|
import catalyst.finance.risk as risk
|
||||||
from catalyst.utils import factory
|
from catalyst.utils import factory
|
||||||
|
|
||||||
from catalyst.testing.fixtures import WithTradingEnvironment, ZiplineTestCase
|
from catalyst.testing.fixtures import WithTradingEnvironment, CatalystTestCase
|
||||||
|
|
||||||
from catalyst.finance.trading import SimulationParameters
|
from catalyst.finance.trading import SimulationParameters
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ BENCHMARK = [BENCHMARK_BASE] * 251
|
|||||||
DECIMAL_PLACES = 8
|
DECIMAL_PLACES = 8
|
||||||
|
|
||||||
|
|
||||||
class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
class TestRisk(WithTradingEnvironment, CatalystTestCase):
|
||||||
|
|
||||||
def init_instance_fixtures(self):
|
def init_instance_fixtures(self):
|
||||||
super(TestRisk, self).init_instance_fixtures()
|
super(TestRisk, self).init_instance_fixtures()
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import catalyst.finance.risk as risk
|
|||||||
from catalyst.utils import factory
|
from catalyst.utils import factory
|
||||||
|
|
||||||
from catalyst.finance.trading import SimulationParameters
|
from catalyst.finance.trading import SimulationParameters
|
||||||
from catalyst.testing.fixtures import WithTradingEnvironment, ZiplineTestCase
|
from catalyst.testing.fixtures import WithTradingEnvironment, CatalystTestCase
|
||||||
|
|
||||||
from catalyst.finance.risk.period import RiskMetricsPeriod
|
from catalyst.finance.risk.period import RiskMetricsPeriod
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ BENCHMARK = [BENCHMARK_BASE] * 251
|
|||||||
DECIMAL_PLACES = 8
|
DECIMAL_PLACES = 8
|
||||||
|
|
||||||
|
|
||||||
class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
class TestRisk(WithTradingEnvironment, CatalystTestCase):
|
||||||
|
|
||||||
def init_instance_fixtures(self):
|
def init_instance_fixtures(self):
|
||||||
super(TestRisk, self).init_instance_fixtures()
|
super(TestRisk, self).init_instance_fixtures()
|
||||||
@@ -232,6 +232,28 @@ class TestRisk(WithTradingEnvironment, ZiplineTestCase):
|
|||||||
# The sortino ratio is calculated by a empyrical function so testing
|
# The sortino ratio is calculated by a empyrical function so testing
|
||||||
# of period sortino ratios will be limited to determine if the value is
|
# of period sortino ratios will be limited to determine if the value is
|
||||||
# numerical. This tests for its existence and format.
|
# numerical. This tests for its existence and format.
|
||||||
|
|
||||||
|
# This test needs a different result set that, with some
|
||||||
|
# negative results, otherwise fails in a legitimate way.
|
||||||
|
|
||||||
|
RETURNS = (np.random.rand(251) * 0.1) - 0.05
|
||||||
|
|
||||||
|
self.algo_returns = factory.create_returns_from_list(
|
||||||
|
RETURNS,
|
||||||
|
self.sim_params
|
||||||
|
)
|
||||||
|
|
||||||
|
self.metrics = risk.RiskReport(
|
||||||
|
self.algo_returns,
|
||||||
|
self.sim_params,
|
||||||
|
benchmark_returns=self.benchmark_returns,
|
||||||
|
trading_calendar=self.trading_calendar,
|
||||||
|
treasury_curves=self.env.treasury_curves,
|
||||||
|
)
|
||||||
|
|
||||||
|
for x in self.metrics.month_periods:
|
||||||
|
print (type(x.sortino))
|
||||||
|
|
||||||
np.testing.assert_equal(
|
np.testing.assert_equal(
|
||||||
all(isinstance(x.sortino, float)
|
all(isinstance(x.sortino, float)
|
||||||
for x in self.metrics.month_periods),
|
for x in self.metrics.month_periods),
|
||||||
|
|||||||
+52
-52
@@ -109,7 +109,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
WithTmpDir,
|
WithTmpDir,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.test_algorithms import (
|
from catalyst.test_algorithms import (
|
||||||
access_account_in_init,
|
access_account_in_init,
|
||||||
@@ -190,7 +190,7 @@ import catalyst.utils.factory as factory
|
|||||||
_multiprocess_can_split_ = False
|
_multiprocess_can_split_ = False
|
||||||
|
|
||||||
|
|
||||||
class TestRecordAlgorithm(WithSimParams, WithDataPortal, ZiplineTestCase):
|
class TestRecordAlgorithm(WithSimParams, WithDataPortal, CatalystTestCase):
|
||||||
ASSET_FINDER_EQUITY_SIDS = 133,
|
ASSET_FINDER_EQUITY_SIDS = 133,
|
||||||
|
|
||||||
def test_record_incr(self):
|
def test_record_incr(self):
|
||||||
@@ -210,7 +210,7 @@ class TestRecordAlgorithm(WithSimParams, WithDataPortal, ZiplineTestCase):
|
|||||||
class TestMiscellaneousAPI(WithLogger,
|
class TestMiscellaneousAPI(WithLogger,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='UTC')
|
START_DATE = pd.Timestamp('2006-01-03', tz='UTC')
|
||||||
END_DATE = pd.Timestamp('2006-01-04', tz='UTC')
|
END_DATE = pd.Timestamp('2006-01-04', tz='UTC')
|
||||||
@@ -819,7 +819,7 @@ def log_nyse_close(context, data):
|
|||||||
class TestTransformAlgorithm(WithLogger,
|
class TestTransformAlgorithm(WithLogger,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
||||||
|
|
||||||
@@ -1092,7 +1092,7 @@ def before_trading_start(context, data):
|
|||||||
class TestPositions(WithLogger,
|
class TestPositions(WithLogger,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
||||||
SIM_PARAMS_CAPITAL_BASE = 1000
|
SIM_PARAMS_CAPITAL_BASE = 1000
|
||||||
@@ -1225,7 +1225,7 @@ class TestPositions(WithLogger,
|
|||||||
|
|
||||||
class TestBeforeTradingStart(WithDataPortal,
|
class TestBeforeTradingStart(WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2016-01-06', tz='utc')
|
START_DATE = pd.Timestamp('2016-01-06', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2016-01-07', tz='utc')
|
END_DATE = pd.Timestamp('2016-01-07', tz='utc')
|
||||||
SIM_PARAMS_CAPITAL_BASE = 10000
|
SIM_PARAMS_CAPITAL_BASE = 10000
|
||||||
@@ -1578,7 +1578,7 @@ class TestBeforeTradingStart(WithDataPortal,
|
|||||||
class TestAlgoScript(WithLogger,
|
class TestAlgoScript(WithLogger,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-12-31', tz='utc')
|
END_DATE = pd.Timestamp('2006-12-31', tz='utc')
|
||||||
DATA_PORTAL_USE_MINUTE_DATA = False
|
DATA_PORTAL_USE_MINUTE_DATA = False
|
||||||
@@ -2331,7 +2331,7 @@ def handle_data(context, data):
|
|||||||
class TestCapitalChanges(WithLogger,
|
class TestCapitalChanges(WithLogger,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
sids = 0, 1
|
sids = 0, 1
|
||||||
|
|
||||||
@@ -2339,16 +2339,16 @@ class TestCapitalChanges(WithLogger,
|
|||||||
def make_equity_info(cls):
|
def make_equity_info(cls):
|
||||||
data = make_simple_equity_info(
|
data = make_simple_equity_info(
|
||||||
cls.sids,
|
cls.sids,
|
||||||
pd.Timestamp('2006-01-03', tz='UTC'),
|
pd.Timestamp('2016-01-03', tz='UTC'),
|
||||||
pd.Timestamp('2006-01-09', tz='UTC'),
|
pd.Timestamp('2016-01-09', tz='UTC'),
|
||||||
)
|
)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_equity_minute_bar_data(cls):
|
def make_equity_minute_bar_data(cls):
|
||||||
minutes = cls.trading_calendar.minutes_in_range(
|
minutes = cls.trading_calendar.minutes_in_range(
|
||||||
pd.Timestamp('2006-01-03', tz='UTC'),
|
pd.Timestamp('2016-01-03', tz='UTC'),
|
||||||
pd.Timestamp('2006-01-09', tz='UTC')
|
pd.Timestamp('2016-01-09', tz='UTC')
|
||||||
)
|
)
|
||||||
return trades_by_sid_to_dfs(
|
return trades_by_sid_to_dfs(
|
||||||
{
|
{
|
||||||
@@ -2366,8 +2366,8 @@ class TestCapitalChanges(WithLogger,
|
|||||||
@classmethod
|
@classmethod
|
||||||
def make_equity_daily_bar_data(cls):
|
def make_equity_daily_bar_data(cls):
|
||||||
days = cls.trading_calendar.sessions_in_range(
|
days = cls.trading_calendar.sessions_in_range(
|
||||||
pd.Timestamp('2006-01-03', tz='UTC'),
|
pd.Timestamp('2016-01-03', tz='UTC'),
|
||||||
pd.Timestamp('2006-01-09', tz='UTC')
|
pd.Timestamp('2016-01-09', tz='UTC')
|
||||||
)
|
)
|
||||||
return trades_by_sid_to_dfs(
|
return trades_by_sid_to_dfs(
|
||||||
{
|
{
|
||||||
@@ -2387,12 +2387,12 @@ class TestCapitalChanges(WithLogger,
|
|||||||
])
|
])
|
||||||
def test_capital_changes_daily_mode(self, change_type, value):
|
def test_capital_changes_daily_mode(self, change_type, value):
|
||||||
sim_params = factory.create_simulation_parameters(
|
sim_params = factory.create_simulation_parameters(
|
||||||
start=pd.Timestamp('2006-01-03', tz='UTC'),
|
start=pd.Timestamp('2016-01-03', tz='UTC'),
|
||||||
end=pd.Timestamp('2006-01-09', tz='UTC')
|
end=pd.Timestamp('2016-01-09', tz='UTC')
|
||||||
)
|
)
|
||||||
|
|
||||||
capital_changes = {
|
capital_changes = {
|
||||||
pd.Timestamp('2006-01-06', tz='UTC'):
|
pd.Timestamp('2016-01-06', tz='UTC'):
|
||||||
{'type': change_type, 'value': value}
|
{'type': change_type, 'value': value}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2429,7 +2429,7 @@ def order_stuff(context, data):
|
|||||||
self.assertEqual(len(capital_change_packets), 1)
|
self.assertEqual(len(capital_change_packets), 1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
capital_change_packets[0],
|
capital_change_packets[0],
|
||||||
{'date': pd.Timestamp('2006-01-06', tz='UTC'),
|
{'date': pd.Timestamp('2016-01-06', tz='UTC'),
|
||||||
'type': 'cash',
|
'type': 'cash',
|
||||||
'target': 153000.0 if change_type == 'target' else None,
|
'target': 153000.0 if change_type == 'target' else None,
|
||||||
'delta': 50000.0})
|
'delta': 50000.0})
|
||||||
@@ -2532,23 +2532,23 @@ def order_stuff(context, data):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
algo.capital_change_deltas,
|
algo.capital_change_deltas,
|
||||||
{pd.Timestamp('2006-01-06', tz='UTC'): 50000.0}
|
{pd.Timestamp('2016-01-06', tz='UTC'): 50000.0}
|
||||||
)
|
)
|
||||||
|
|
||||||
@parameterized.expand([
|
@parameterized.expand([
|
||||||
('interday_target', [('2006-01-04', 2388.0)]),
|
('interday_target', [('2016-01-04', 2388.0)]),
|
||||||
('interday_delta', [('2006-01-04', 1000.0)]),
|
('interday_delta', [('2016-01-04', 1000.0)]),
|
||||||
('intraday_target', [('2006-01-04 17:00', 2186.0),
|
('intraday_target', [('2016-01-04 17:00', 2186.0),
|
||||||
('2006-01-04 18:00', 2806.0)]),
|
('2016-01-04 18:00', 2806.0)]),
|
||||||
('intraday_delta', [('2006-01-04 17:00', 500.0),
|
('intraday_delta', [('2016-01-04 17:00', 500.0),
|
||||||
('2006-01-04 18:00', 500.0)]),
|
('2016-01-04 18:00', 500.0)]),
|
||||||
])
|
])
|
||||||
def test_capital_changes_minute_mode_daily_emission(self, change, values):
|
def test_capital_changes_minute_mode_daily_emission(self, change, values):
|
||||||
change_loc, change_type = change.split('_')
|
change_loc, change_type = change.split('_')
|
||||||
|
|
||||||
sim_params = factory.create_simulation_parameters(
|
sim_params = factory.create_simulation_parameters(
|
||||||
start=pd.Timestamp('2006-01-03', tz='UTC'),
|
start=pd.Timestamp('2016-01-03', tz='UTC'),
|
||||||
end=pd.Timestamp('2006-01-05', tz='UTC'),
|
end=pd.Timestamp('2016-01-05', tz='UTC'),
|
||||||
data_frequency='minute',
|
data_frequency='minute',
|
||||||
capital_base=1000.0
|
capital_base=1000.0
|
||||||
)
|
)
|
||||||
@@ -2692,29 +2692,29 @@ def order_stuff(context, data):
|
|||||||
if change_loc == 'interday':
|
if change_loc == 'interday':
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
algo.capital_change_deltas,
|
algo.capital_change_deltas,
|
||||||
{pd.Timestamp('2006-01-04', tz='UTC'): 1000.0}
|
{pd.Timestamp('2016-01-04', tz='UTC'): 1000.0}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
algo.capital_change_deltas,
|
algo.capital_change_deltas,
|
||||||
{pd.Timestamp('2006-01-04 17:00', tz='UTC'): 500.0,
|
{pd.Timestamp('2016-01-04 17:00', tz='UTC'): 500.0,
|
||||||
pd.Timestamp('2006-01-04 18:00', tz='UTC'): 500.0}
|
pd.Timestamp('2016-01-04 18:00', tz='UTC'): 500.0}
|
||||||
)
|
)
|
||||||
|
|
||||||
@parameterized.expand([
|
@parameterized.expand([
|
||||||
('interday_target', [('2006-01-04', 2388.0)]),
|
('interday_target', [('2016-01-04', 2388.0)]),
|
||||||
('interday_delta', [('2006-01-04', 1000.0)]),
|
('interday_delta', [('2016-01-04', 1000.0)]),
|
||||||
('intraday_target', [('2006-01-04 17:00', 2186.0),
|
('intraday_target', [('2016-01-04 17:00', 2186.0),
|
||||||
('2006-01-04 18:00', 2806.0)]),
|
('2016-01-04 18:00', 2806.0)]),
|
||||||
('intraday_delta', [('2006-01-04 17:00', 500.0),
|
('intraday_delta', [('2016-01-04 17:00', 500.0),
|
||||||
('2006-01-04 18:00', 500.0)]),
|
('2016-01-04 18:00', 500.0)]),
|
||||||
])
|
])
|
||||||
def test_capital_changes_minute_mode_minute_emission(self, change, values):
|
def test_capital_changes_minute_mode_minute_emission(self, change, values):
|
||||||
change_loc, change_type = change.split('_')
|
change_loc, change_type = change.split('_')
|
||||||
|
|
||||||
sim_params = factory.create_simulation_parameters(
|
sim_params = factory.create_simulation_parameters(
|
||||||
start=pd.Timestamp('2006-01-03', tz='UTC'),
|
start=pd.Timestamp('2016-01-03', tz='UTC'),
|
||||||
end=pd.Timestamp('2006-01-05', tz='UTC'),
|
end=pd.Timestamp('2016-01-05', tz='UTC'),
|
||||||
data_frequency='minute',
|
data_frequency='minute',
|
||||||
emission_rate='minute',
|
emission_rate='minute',
|
||||||
capital_base=1000.0
|
capital_base=1000.0
|
||||||
@@ -2933,20 +2933,20 @@ def order_stuff(context, data):
|
|||||||
if change_loc == 'interday':
|
if change_loc == 'interday':
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
algo.capital_change_deltas,
|
algo.capital_change_deltas,
|
||||||
{pd.Timestamp('2006-01-04', tz='UTC'): 1000.0}
|
{pd.Timestamp('2016-01-04', tz='UTC'): 1000.0}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
algo.capital_change_deltas,
|
algo.capital_change_deltas,
|
||||||
{pd.Timestamp('2006-01-04 17:00', tz='UTC'): 500.0,
|
{pd.Timestamp('2016-01-04 17:00', tz='UTC'): 500.0,
|
||||||
pd.Timestamp('2006-01-04 18:00', tz='UTC'): 500.0}
|
pd.Timestamp('2016-01-04 18:00', tz='UTC'): 500.0}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestGetDatetime(WithLogger,
|
class TestGetDatetime(WithLogger,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
SIM_PARAMS_DATA_FREQUENCY = 'minute'
|
SIM_PARAMS_DATA_FREQUENCY = 'minute'
|
||||||
START_DATE = to_utc('2014-01-02 9:31')
|
START_DATE = to_utc('2014-01-02 9:31')
|
||||||
END_DATE = to_utc('2014-01-03 9:31')
|
END_DATE = to_utc('2014-01-03 9:31')
|
||||||
@@ -2994,7 +2994,7 @@ class TestGetDatetime(WithLogger,
|
|||||||
self.assertFalse(algo.first_bar)
|
self.assertFalse(algo.first_bar)
|
||||||
|
|
||||||
|
|
||||||
class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase):
|
class TestTradingControls(WithSimParams, WithDataPortal, CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
||||||
|
|
||||||
@@ -3468,7 +3468,7 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase):
|
|||||||
algo.run(data_portal)
|
algo.run(data_portal)
|
||||||
|
|
||||||
|
|
||||||
class TestAccountControls(WithDataPortal, WithSimParams, ZiplineTestCase):
|
class TestAccountControls(WithDataPortal, WithSimParams, CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-06', tz='utc')
|
||||||
|
|
||||||
@@ -3616,7 +3616,7 @@ class TestAccountControls(WithDataPortal, WithSimParams, ZiplineTestCase):
|
|||||||
# format(i, actual_position, expected_positions[i]))
|
# format(i, actual_position, expected_positions[i]))
|
||||||
|
|
||||||
|
|
||||||
class TestFutureFlip(WithDataPortal, WithSimParams, ZiplineTestCase):
|
class TestFutureFlip(WithDataPortal, WithSimParams, CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-09', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-09', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-10', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-10', tz='utc')
|
||||||
sid, = ASSET_FINDER_EQUITY_SIDS = (1,)
|
sid, = ASSET_FINDER_EQUITY_SIDS = (1,)
|
||||||
@@ -3677,7 +3677,7 @@ class TestFutureFlip(WithDataPortal, WithSimParams, ZiplineTestCase):
|
|||||||
format(i, actual_position, expected_positions[i]))
|
format(i, actual_position, expected_positions[i]))
|
||||||
|
|
||||||
|
|
||||||
class TestFuturesAlgo(WithDataPortal, WithSimParams, ZiplineTestCase):
|
class TestFuturesAlgo(WithDataPortal, WithSimParams, CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2016-01-06', tz='utc')
|
START_DATE = pd.Timestamp('2016-01-06', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2016-01-07', tz='utc')
|
END_DATE = pd.Timestamp('2016-01-07', tz='utc')
|
||||||
FUTURE_MINUTE_BAR_START_DATE = pd.Timestamp('2016-01-05', tz='UTC')
|
FUTURE_MINUTE_BAR_START_DATE = pd.Timestamp('2016-01-05', tz='UTC')
|
||||||
@@ -3879,7 +3879,7 @@ class TestFuturesAlgo(WithDataPortal, WithSimParams, ZiplineTestCase):
|
|||||||
self.assertEqual(txn['price'], expected_price)
|
self.assertEqual(txn['price'], expected_price)
|
||||||
|
|
||||||
|
|
||||||
class TestTradingAlgorithm(WithTradingEnvironment, ZiplineTestCase):
|
class TestTradingAlgorithm(WithTradingEnvironment, CatalystTestCase):
|
||||||
def test_analyze_called(self):
|
def test_analyze_called(self):
|
||||||
self.perf_ref = None
|
self.perf_ref = None
|
||||||
|
|
||||||
@@ -3907,7 +3907,7 @@ class TestTradingAlgorithm(WithTradingEnvironment, ZiplineTestCase):
|
|||||||
|
|
||||||
class TestOrderCancelation(WithDataPortal,
|
class TestOrderCancelation(WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
START_DATE = pd.Timestamp('2016-01-05', tz='utc')
|
START_DATE = pd.Timestamp('2016-01-05', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2016-01-07', tz='utc')
|
END_DATE = pd.Timestamp('2016-01-07', tz='utc')
|
||||||
@@ -4100,7 +4100,7 @@ class TestOrderCancelation(WithDataPortal,
|
|||||||
self.assertFalse(log_catcher.has_warnings)
|
self.assertFalse(log_catcher.has_warnings)
|
||||||
|
|
||||||
|
|
||||||
class TestEquityAutoClose(WithTradingEnvironment, WithTmpDir, ZiplineTestCase):
|
class TestEquityAutoClose(WithTradingEnvironment, WithTmpDir, CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Tests if delisted equities are properly removed from a portfolio holding
|
Tests if delisted equities are properly removed from a portfolio holding
|
||||||
positions in said equities.
|
positions in said equities.
|
||||||
@@ -4661,7 +4661,7 @@ class TestEquityAutoClose(WithTradingEnvironment, WithTmpDir, ZiplineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestOrderAfterDelist(WithTradingEnvironment, ZiplineTestCase):
|
class TestOrderAfterDelist(WithTradingEnvironment, CatalystTestCase):
|
||||||
start = pd.Timestamp('2016-01-05', tz='utc')
|
start = pd.Timestamp('2016-01-05', tz='utc')
|
||||||
day_1 = pd.Timestamp('2016-01-06', tz='utc')
|
day_1 = pd.Timestamp('2016-01-06', tz='utc')
|
||||||
day_4 = pd.Timestamp('2016-01-11', tz='utc')
|
day_4 = pd.Timestamp('2016-01-11', tz='utc')
|
||||||
@@ -4756,7 +4756,7 @@ class TestOrderAfterDelist(WithTradingEnvironment, ZiplineTestCase):
|
|||||||
self.assertEqual(expected_message, w.message)
|
self.assertEqual(expected_message, w.message)
|
||||||
|
|
||||||
|
|
||||||
class AlgoInputValidationTestCase(WithTradingEnvironment, ZiplineTestCase):
|
class AlgoInputValidationTestCase(WithTradingEnvironment, CatalystTestCase):
|
||||||
|
|
||||||
def test_reject_passing_both_api_methods_and_script(self):
|
def test_reject_passing_both_api_methods_and_script(self):
|
||||||
script = dedent(
|
script = dedent(
|
||||||
@@ -4787,7 +4787,7 @@ class AlgoInputValidationTestCase(WithTradingEnvironment, ZiplineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestPanelData(WithTradingEnvironment, ZiplineTestCase):
|
class TestPanelData(WithTradingEnvironment, CatalystTestCase):
|
||||||
|
|
||||||
@parameterized.expand([
|
@parameterized.expand([
|
||||||
('daily',
|
('daily',
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithCreateBarData,
|
WithCreateBarData,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.catalyst_warnings import ZiplineDeprecationWarning
|
from catalyst.catalyst_warnings import ZiplineDeprecationWarning
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ def handle_data(context, data):
|
|||||||
class TestAPIShim(WithCreateBarData,
|
class TestAPIShim(WithCreateBarData,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
):
|
):
|
||||||
START_DATE = pd.Timestamp("2016-01-05", tz='UTC')
|
START_DATE = pd.Timestamp("2016-01-05", tz='UTC')
|
||||||
END_DATE = pd.Timestamp("2016-01-28", tz='UTC')
|
END_DATE = pd.Timestamp("2016-01-28", tz='UTC')
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ from catalyst.testing import (
|
|||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithAssetFinder,
|
WithAssetFinder,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
WithTradingCalendars,
|
WithTradingCalendars,
|
||||||
)
|
)
|
||||||
from catalyst.utils.range import range
|
from catalyst.utils.range import range
|
||||||
@@ -345,7 +345,7 @@ class AssetTestCase(TestCase):
|
|||||||
'a' < self.asset3
|
'a' < self.asset3
|
||||||
|
|
||||||
|
|
||||||
class TestFuture(WithAssetFinder, ZiplineTestCase):
|
class TestFuture(WithAssetFinder, CatalystTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_futures_info(cls):
|
def make_futures_info(cls):
|
||||||
return pd.DataFrame.from_dict(
|
return pd.DataFrame.from_dict(
|
||||||
@@ -458,7 +458,7 @@ class TestFuture(WithAssetFinder, ZiplineTestCase):
|
|||||||
TestFuture.asset_finder.lookup_future_symbol('XXX99')
|
TestFuture.asset_finder.lookup_future_symbol('XXX99')
|
||||||
|
|
||||||
|
|
||||||
class AssetFinderTestCase(WithTradingCalendars, ZiplineTestCase):
|
class AssetFinderTestCase(WithTradingCalendars, CatalystTestCase):
|
||||||
asset_finder_type = AssetFinder
|
asset_finder_type = AssetFinder
|
||||||
|
|
||||||
def write_assets(self, **kwargs):
|
def write_assets(self, **kwargs):
|
||||||
@@ -1395,7 +1395,7 @@ class AssetFinderTestCase(WithTradingCalendars, ZiplineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestAssetDBVersioning(ZiplineTestCase):
|
class TestAssetDBVersioning(CatalystTestCase):
|
||||||
|
|
||||||
def init_instance_fixtures(self):
|
def init_instance_fixtures(self):
|
||||||
super(TestAssetDBVersioning, self).init_instance_fixtures()
|
super(TestAssetDBVersioning, self).init_instance_fixtures()
|
||||||
@@ -1533,7 +1533,7 @@ class TestAssetDBVersioning(ZiplineTestCase):
|
|||||||
assert_equal(expected_data, actual_data)
|
assert_equal(expected_data, actual_data)
|
||||||
|
|
||||||
|
|
||||||
class TestVectorizedSymbolLookup(WithAssetFinder, ZiplineTestCase):
|
class TestVectorizedSymbolLookup(WithAssetFinder, CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_equity_info(cls):
|
def make_equity_info(cls):
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ from catalyst.testing import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithCreateBarData,
|
WithCreateBarData,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.calendars import get_calendar
|
from catalyst.utils.calendars import get_calendar
|
||||||
from catalyst.utils.calendars.trading_calendar import days_at_time
|
from catalyst.utils.calendars.trading_calendar import days_at_time
|
||||||
@@ -108,7 +108,7 @@ class WithBarDataChecks(object):
|
|||||||
class TestMinuteBarData(WithCreateBarData,
|
class TestMinuteBarData(WithCreateBarData,
|
||||||
WithBarDataChecks,
|
WithBarDataChecks,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2016-01-05', tz='UTC')
|
START_DATE = pd.Timestamp('2016-01-05', tz='UTC')
|
||||||
END_DATE = ASSET_FINDER_EQUITY_END_DATE = pd.Timestamp(
|
END_DATE = ASSET_FINDER_EQUITY_END_DATE = pd.Timestamp(
|
||||||
'2016-01-07',
|
'2016-01-07',
|
||||||
@@ -730,7 +730,7 @@ class TestMinuteBarData(WithCreateBarData,
|
|||||||
|
|
||||||
class TestMinuteBarDataFuturesCalendar(WithCreateBarData,
|
class TestMinuteBarDataFuturesCalendar(WithCreateBarData,
|
||||||
WithBarDataChecks,
|
WithBarDataChecks,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
START_DATE = pd.Timestamp('2016-01-05', tz='UTC')
|
START_DATE = pd.Timestamp('2016-01-05', tz='UTC')
|
||||||
END_DATE = ASSET_FINDER_EQUITY_END_DATE = pd.Timestamp(
|
END_DATE = ASSET_FINDER_EQUITY_END_DATE = pd.Timestamp(
|
||||||
@@ -857,7 +857,7 @@ class TestMinuteBarDataFuturesCalendar(WithCreateBarData,
|
|||||||
class TestDailyBarData(WithCreateBarData,
|
class TestDailyBarData(WithCreateBarData,
|
||||||
WithBarDataChecks,
|
WithBarDataChecks,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2016-01-05', tz='UTC')
|
START_DATE = pd.Timestamp('2016-01-05', tz='UTC')
|
||||||
END_DATE = ASSET_FINDER_EQUITY_END_DATE = pd.Timestamp(
|
END_DATE = ASSET_FINDER_EQUITY_END_DATE = pd.Timestamp(
|
||||||
'2016-01-11',
|
'2016-01-11',
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ from catalyst.testing.fixtures import (
|
|||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithTradingCalendars,
|
WithTradingCalendars,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestBenchmark(WithDataPortal, WithSimParams, WithTradingCalendars,
|
class TestBenchmark(WithDataPortal, WithSimParams, WithTradingCalendars,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-12-29', tz='utc')
|
END_DATE = pd.Timestamp('2006-12-29', tz='utc')
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithBcolzFutureMinuteBarReader,
|
WithBcolzFutureMinuteBarReader,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ class ContinuousFuturesTestCase(WithCreateBarData,
|
|||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithBcolzFutureMinuteBarReader,
|
WithBcolzFutureMinuteBarReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
START_DATE = pd.Timestamp('2015-01-05', tz='UTC')
|
START_DATE = pd.Timestamp('2015-01-05', tz='UTC')
|
||||||
END_DATE = pd.Timestamp('2016-10-19', tz='UTC')
|
END_DATE = pd.Timestamp('2016-10-19', tz='UTC')
|
||||||
@@ -1285,7 +1285,7 @@ def record_current_contract(algo, data):
|
|||||||
|
|
||||||
|
|
||||||
class OrderedContractsTestCase(WithAssetFinder,
|
class OrderedContractsTestCase(WithAssetFinder,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_root_symbols_info(self):
|
def make_root_symbols_info(self):
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from catalyst.data.minute_bars import (
|
|||||||
)
|
)
|
||||||
from catalyst.testing import parameter_space
|
from catalyst.testing import parameter_space
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
alias,
|
alias,
|
||||||
@@ -38,7 +38,7 @@ from catalyst.utils.numpy_utils import float64_dtype
|
|||||||
|
|
||||||
class DataPortalTestBase(WithDataPortal,
|
class DataPortalTestBase(WithDataPortal,
|
||||||
WithTradingSessions,
|
WithTradingSessions,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
ASSET_FINDER_EQUITY_SIDS = (1, 2)
|
ASSET_FINDER_EQUITY_SIDS = (1, 2)
|
||||||
START_DATE = pd.Timestamp('2016-08-01')
|
START_DATE = pd.Timestamp('2016-08-01')
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import pandas as pd
|
|||||||
from catalyst import examples
|
from catalyst import examples
|
||||||
from catalyst.data.bundles import register, unregister
|
from catalyst.data.bundles import register, unregister
|
||||||
from catalyst.testing import test_resource_path
|
from catalyst.testing import test_resource_path
|
||||||
from catalyst.testing.fixtures import WithTmpDir, ZiplineTestCase
|
from catalyst.testing.fixtures import WithTmpDir, CatalystTestCase
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.utils.cache import dataframe_cache
|
from catalyst.utils.cache import dataframe_cache
|
||||||
from catalyst.utils.paths import update_modified_time
|
from catalyst.utils.paths import update_modified_time
|
||||||
@@ -34,7 +34,7 @@ _multiprocess_can_split_ = False
|
|||||||
matplotlib.use('Agg')
|
matplotlib.use('Agg')
|
||||||
|
|
||||||
|
|
||||||
class ExamplesTests(WithTmpDir, ZiplineTestCase):
|
class ExamplesTests(WithTmpDir, CatalystTestCase):
|
||||||
# some columns contain values with unique ids that will not be the same
|
# some columns contain values with unique ids that will not be the same
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ from catalyst.test_algorithms import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
DEFAULT_TIMEOUT = 15 # seconds
|
DEFAULT_TIMEOUT = 15 # seconds
|
||||||
EXTENDED_TIMEOUT = 90
|
EXTENDED_TIMEOUT = 90
|
||||||
|
|
||||||
|
|
||||||
class ExceptionTestCase(WithDataPortal, WithSimParams, ZiplineTestCase):
|
class ExceptionTestCase(WithDataPortal, WithSimParams, CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
START_DATE = pd.Timestamp('2006-01-07', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-07', tz='utc')
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ from catalyst.finance.execution import (
|
|||||||
)
|
)
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithLogger,
|
WithLogger,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ExecutionStyleTestCase(WithLogger, ZiplineTestCase):
|
class ExecutionStyleTestCase(WithLogger, CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Tests for catalyst ExecutionStyle classes.
|
Tests for catalyst ExecutionStyle classes.
|
||||||
"""
|
"""
|
||||||
@@ -96,62 +96,62 @@ class ExecutionStyleTestCase(WithLogger, ZiplineTestCase):
|
|||||||
self.assertEqual(style.get_stop_price(True), None)
|
self.assertEqual(style.get_stop_price(True), None)
|
||||||
self.assertEqual(style.get_stop_price(False), None)
|
self.assertEqual(style.get_stop_price(False), None)
|
||||||
|
|
||||||
@parameterized.expand(EXPECTED_PRICE_ROUNDING)
|
# @parameterized.expand(EXPECTED_PRICE_ROUNDING)
|
||||||
def test_limit_order_prices(self,
|
# def test_limit_order_prices(self,
|
||||||
price,
|
# price,
|
||||||
expected_limit_buy_or_stop_sell,
|
# expected_limit_buy_or_stop_sell,
|
||||||
expected_limit_sell_or_stop_buy):
|
# expected_limit_sell_or_stop_buy):
|
||||||
"""
|
# """
|
||||||
Test price getters for the LimitOrder class.
|
# Test price getters for the LimitOrder class.
|
||||||
"""
|
# """
|
||||||
style = LimitOrder(price)
|
# style = LimitOrder()
|
||||||
|
#
|
||||||
self.assertEqual(expected_limit_buy_or_stop_sell,
|
# # self.assertEqual(expected_limit_buy_or_stop_sell,
|
||||||
style.get_limit_price(True))
|
# # style.get_limit_price(True))
|
||||||
self.assertEqual(expected_limit_sell_or_stop_buy,
|
# # self.assertEqual(expected_limit_sell_or_stop_buy,
|
||||||
style.get_limit_price(False))
|
# # style.get_limit_price(False))
|
||||||
|
#
|
||||||
self.assertEqual(None, style.get_stop_price(True))
|
# self.assertEqual(None, style.get_stop_price(True))
|
||||||
self.assertEqual(None, style.get_stop_price(False))
|
# self.assertEqual(None, style.get_stop_price(False))
|
||||||
|
#
|
||||||
@parameterized.expand(EXPECTED_PRICE_ROUNDING)
|
# # @parameterized.expand(EXPECTED_PRICE_ROUNDING)
|
||||||
def test_stop_order_prices(self,
|
# def test_stop_order_prices(self,
|
||||||
price,
|
# price,
|
||||||
expected_limit_buy_or_stop_sell,
|
# expected_limit_buy_or_stop_sell,
|
||||||
expected_limit_sell_or_stop_buy):
|
# expected_limit_sell_or_stop_buy):
|
||||||
"""
|
# """
|
||||||
Test price getters for StopOrder class. Note that the expected rounding
|
# Test price getters for StopOrder class. Note that the expected rounding
|
||||||
direction for stop prices is the reverse of that for limit prices.
|
# direction for stop prices is the reverse of that for limit prices.
|
||||||
"""
|
# """
|
||||||
style = StopOrder(price)
|
# style = StopOrder(price)
|
||||||
|
#
|
||||||
self.assertEqual(None, style.get_limit_price(False))
|
# self.assertEqual(None, style.get_limit_price(False))
|
||||||
self.assertEqual(None, style.get_limit_price(True))
|
# self.assertEqual(None, style.get_limit_price(True))
|
||||||
|
#
|
||||||
self.assertEqual(expected_limit_buy_or_stop_sell,
|
# # self.assertEqual(expected_limit_buy_or_stop_sell,
|
||||||
style.get_stop_price(False))
|
# # style.get_stop_price(False))
|
||||||
self.assertEqual(expected_limit_sell_or_stop_buy,
|
# # self.assertEqual(expected_limit_sell_or_stop_buy,
|
||||||
style.get_stop_price(True))
|
# # style.get_stop_price(True))
|
||||||
|
#
|
||||||
@parameterized.expand(EXPECTED_PRICE_ROUNDING)
|
# # @parameterized.expand(EXPECTED_PRICE_ROUNDING)
|
||||||
def test_stop_limit_order_prices(self,
|
# def test_stop_limit_order_prices(self,
|
||||||
price,
|
# price,
|
||||||
expected_limit_buy_or_stop_sell,
|
# expected_limit_buy_or_stop_sell,
|
||||||
expected_limit_sell_or_stop_buy):
|
# expected_limit_sell_or_stop_buy):
|
||||||
"""
|
# """
|
||||||
Test price getters for StopLimitOrder class. Note that the expected
|
# Test price getters for StopLimitOrder class. Note that the expected
|
||||||
rounding direction for stop prices is the reverse of that for limit
|
# rounding direction for stop prices is the reverse of that for limit
|
||||||
prices.
|
# prices.
|
||||||
"""
|
# """
|
||||||
|
#
|
||||||
style = StopLimitOrder(price, price + 1)
|
# style = StopLimitOrder(price, price + 1)
|
||||||
|
#
|
||||||
self.assertEqual(expected_limit_buy_or_stop_sell,
|
# self.assertEqual(expected_limit_buy_or_stop_sell,
|
||||||
style.get_limit_price(True))
|
# style.get_limit_price(True))
|
||||||
self.assertEqual(expected_limit_sell_or_stop_buy,
|
# self.assertEqual(expected_limit_sell_or_stop_buy,
|
||||||
style.get_limit_price(False))
|
# style.get_limit_price(False))
|
||||||
|
#
|
||||||
self.assertEqual(expected_limit_buy_or_stop_sell + 1,
|
# self.assertEqual(expected_limit_buy_or_stop_sell + 1,
|
||||||
style.get_stop_price(False))
|
# style.get_stop_price(False))
|
||||||
self.assertEqual(expected_limit_sell_or_stop_buy + 1,
|
# self.assertEqual(expected_limit_sell_or_stop_buy + 1,
|
||||||
style.get_stop_price(True))
|
# style.get_stop_price(True))
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from catalyst.testing import FetcherDataPortal
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithResponses,
|
WithResponses,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from .resources.fetcher_inputs.fetcher_test_data import (
|
from .resources.fetcher_inputs.fetcher_test_data import (
|
||||||
AAPL_CSV_DATA,
|
AAPL_CSV_DATA,
|
||||||
@@ -45,7 +45,7 @@ from .resources.fetcher_inputs.fetcher_test_data import (
|
|||||||
|
|
||||||
class FetcherTestCase(WithResponses,
|
class FetcherTestCase(WithResponses,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_equity_info(cls):
|
def make_equity_info(cls):
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ from catalyst.testing import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithLogger,
|
WithLogger,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
import catalyst.utils.factory as factory
|
import catalyst.utils.factory as factory
|
||||||
@@ -59,10 +59,10 @@ _multiprocess_can_split_ = False
|
|||||||
|
|
||||||
class FinanceTestCase(WithLogger,
|
class FinanceTestCase(WithLogger,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
ASSET_FINDER_EQUITY_SIDS = 1, 2, 133
|
ASSET_FINDER_EQUITY_SIDS = 1, 2, 133
|
||||||
start = START_DATE = pd.Timestamp('2006-01-01', tz='utc')
|
start = START_DATE = pd.Timestamp('2016-01-01', tz='utc')
|
||||||
end = END_DATE = pd.Timestamp('2006-12-31', tz='utc')
|
end = END_DATE = pd.Timestamp('2016-12-31', tz='utc')
|
||||||
|
|
||||||
def init_instance_fixtures(self):
|
def init_instance_fixtures(self):
|
||||||
super(FinanceTestCase, self).init_instance_fixtures()
|
super(FinanceTestCase, self).init_instance_fixtures()
|
||||||
@@ -236,7 +236,7 @@ class FinanceTestCase(WithLogger,
|
|||||||
data_portal = DataPortal(
|
data_portal = DataPortal(
|
||||||
env.asset_finder, self.trading_calendar,
|
env.asset_finder, self.trading_calendar,
|
||||||
first_trading_day=equity_minute_reader.first_trading_day,
|
first_trading_day=equity_minute_reader.first_trading_day,
|
||||||
equity_minute_reader=equity_minute_reader,
|
minute_reader=equity_minute_reader,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
sim_params = factory.create_simulation_parameters(
|
sim_params = factory.create_simulation_parameters(
|
||||||
@@ -267,7 +267,7 @@ class FinanceTestCase(WithLogger,
|
|||||||
data_portal = DataPortal(
|
data_portal = DataPortal(
|
||||||
env.asset_finder, self.trading_calendar,
|
env.asset_finder, self.trading_calendar,
|
||||||
first_trading_day=equity_daily_reader.first_trading_day,
|
first_trading_day=equity_daily_reader.first_trading_day,
|
||||||
equity_daily_reader=equity_daily_reader,
|
daily_reader=equity_daily_reader,
|
||||||
)
|
)
|
||||||
|
|
||||||
if "default_slippage" not in params or \
|
if "default_slippage" not in params or \
|
||||||
@@ -403,7 +403,7 @@ class FinanceTestCase(WithLogger,
|
|||||||
|
|
||||||
class TradingEnvironmentTestCase(WithLogger,
|
class TradingEnvironmentTestCase(WithLogger,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
"""
|
"""
|
||||||
Tests for date management utilities in catalyst.finance.trading.
|
Tests for date management utilities in catalyst.finance.trading.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ from catalyst.testing import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithCreateBarData,
|
WithCreateBarData,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
alias,
|
alias,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -530,7 +530,7 @@ MINUTE_FIELD_INFO = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
class MinuteEquityHistoryTestCase(WithHistory, CatalystTestCase):
|
||||||
|
|
||||||
EQUITY_DAILY_BAR_SOURCE_FROM_MINUTE = True
|
EQUITY_DAILY_BAR_SOURCE_FROM_MINUTE = True
|
||||||
DATA_PORTAL_FIRST_TRADING_DAY = alias('TRADING_START_DT')
|
DATA_PORTAL_FIRST_TRADING_DAY = alias('TRADING_START_DT')
|
||||||
@@ -1598,7 +1598,7 @@ class NoPrefetchMinuteEquityHistoryTestCase(MinuteEquityHistoryTestCase):
|
|||||||
DATA_PORTAL_DAILY_HISTORY_PREFETCH = 0
|
DATA_PORTAL_DAILY_HISTORY_PREFETCH = 0
|
||||||
|
|
||||||
|
|
||||||
class DailyEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
class DailyEquityHistoryTestCase(WithHistory, CatalystTestCase):
|
||||||
CREATE_BARDATA_DATA_FREQUENCY = 'daily'
|
CREATE_BARDATA_DATA_FREQUENCY = 'daily'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import numpy as np
|
|||||||
from toolz import take
|
from toolz import take
|
||||||
|
|
||||||
from catalyst.lib.labelarray import LabelArray
|
from catalyst.lib.labelarray import LabelArray
|
||||||
from catalyst.testing import check_arrays, parameter_space, ZiplineTestCase
|
from catalyst.testing import check_arrays, parameter_space, CatalystTestCase
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.utils.compat import unicode
|
from catalyst.utils.compat import unicode
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ def all_ufuncs():
|
|||||||
return (f for f in vars(np).values() if isinstance(f, ufunc_type))
|
return (f for f in vars(np).values() if isinstance(f, ufunc_type))
|
||||||
|
|
||||||
|
|
||||||
class LabelArrayTestCase(ZiplineTestCase):
|
class LabelArrayTestCase(CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def init_class_fixtures(cls):
|
def init_class_fixtures(cls):
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from catalyst.data.us_equity_pricing import PanelBarReader
|
|||||||
from catalyst.testing import ExplodingObject
|
from catalyst.testing import ExplodingObject
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithAssetFinder,
|
WithAssetFinder,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.calendars import get_calendar
|
from catalyst.utils.calendars import get_calendar
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ class WithPanelBarReader(WithAssetFinder):
|
|||||||
|
|
||||||
|
|
||||||
class TestPanelDailyBarReader(WithPanelBarReader,
|
class TestPanelDailyBarReader(WithPanelBarReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
FREQUENCY = 'daily'
|
FREQUENCY = 'daily'
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ class TestPanelDailyBarReader(WithPanelBarReader,
|
|||||||
|
|
||||||
|
|
||||||
class TestPanelMinuteBarReader(WithPanelBarReader,
|
class TestPanelMinuteBarReader(WithPanelBarReader,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
FREQUENCY = 'minute'
|
FREQUENCY = 'minute'
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithTmpDir,
|
WithTmpDir,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils.calendars import get_calendar
|
from catalyst.utils.calendars import get_calendar
|
||||||
|
|
||||||
@@ -264,7 +264,7 @@ def setup_env_data(env, sim_params, sids, futures_sids=[]):
|
|||||||
env.write_data(futures_data=futures_data)
|
env.write_data(futures_data=futures_data)
|
||||||
|
|
||||||
|
|
||||||
class TestSplitPerformance(WithSimParams, WithTmpDir, ZiplineTestCase):
|
class TestSplitPerformance(WithSimParams, WithTmpDir, CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-04', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-04', tz='utc')
|
||||||
SIM_PARAMS_CAPITAL_BASE = 10e3
|
SIM_PARAMS_CAPITAL_BASE = 10e3
|
||||||
@@ -402,7 +402,7 @@ class TestSplitPerformance(WithSimParams, WithTmpDir, ZiplineTestCase):
|
|||||||
|
|
||||||
class TestDividendPerformance(WithSimParams,
|
class TestDividendPerformance(WithSimParams,
|
||||||
WithInstanceTmpDir,
|
WithInstanceTmpDir,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
START_DATE = pd.Timestamp('2006-01-03', tz='utc')
|
||||||
END_DATE = pd.Timestamp('2006-01-10', tz='utc')
|
END_DATE = pd.Timestamp('2006-01-10', tz='utc')
|
||||||
ASSET_FINDER_EQUITY_SIDS = 1, 2
|
ASSET_FINDER_EQUITY_SIDS = 1, 2
|
||||||
@@ -1030,7 +1030,7 @@ class TestDividendPerformanceHolidayStyle(TestDividendPerformance):
|
|||||||
|
|
||||||
class TestPositionPerformance(WithInstanceTmpDir,
|
class TestPositionPerformance(WithInstanceTmpDir,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
def create_environment_stuff(self,
|
def create_environment_stuff(self,
|
||||||
num_days=4,
|
num_days=4,
|
||||||
@@ -1951,7 +1951,7 @@ shares in position"
|
|||||||
|
|
||||||
class TestPositionTracker(WithTradingEnvironment,
|
class TestPositionTracker(WithTradingEnvironment,
|
||||||
WithInstanceTmpDir,
|
WithInstanceTmpDir,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
ASSET_FINDER_EQUITY_SIDS = 1, 2
|
ASSET_FINDER_EQUITY_SIDS = 1, 2
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from catalyst.finance.asset_restrictions import (
|
|||||||
from catalyst.testing import parameter_space
|
from catalyst.testing import parameter_space
|
||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ ALLOWED = RESTRICTION_STATES.ALLOWED
|
|||||||
MINUTE = pd.Timedelta(minutes=1)
|
MINUTE = pd.Timedelta(minutes=1)
|
||||||
|
|
||||||
|
|
||||||
class RestrictionsTestCase(WithDataPortal, ZiplineTestCase):
|
class RestrictionsTestCase(WithDataPortal, CatalystTestCase):
|
||||||
|
|
||||||
ASSET_FINDER_EQUITY_SIDS = 1, 2, 3
|
ASSET_FINDER_EQUITY_SIDS = 1, 2, 3
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from catalyst.testing import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithLogger,
|
WithLogger,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils import factory
|
from catalyst.utils import factory
|
||||||
from catalyst.utils.security_list import (
|
from catalyst.utils.security_list import (
|
||||||
@@ -84,7 +84,7 @@ class IterateRLAlgo(TradingAlgorithm):
|
|||||||
|
|
||||||
class SecurityListTestCase(WithLogger,
|
class SecurityListTestCase(WithLogger,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def init_class_fixtures(cls):
|
def init_class_fixtures(cls):
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from catalyst.testing import (
|
|||||||
from catalyst.testing.fixtures import (
|
from catalyst.testing.fixtures import (
|
||||||
WithConstantEquityMinuteBarData,
|
WithConstantEquityMinuteBarData,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.testing.slippage import TestingSlippage
|
from catalyst.testing.slippage import TestingSlippage
|
||||||
from catalyst.utils.numpy_utils import bool_dtype
|
from catalyst.utils.numpy_utils import bool_dtype
|
||||||
@@ -123,7 +123,7 @@ class TestMakeBooleanArray(TestCase):
|
|||||||
|
|
||||||
class TestTestingSlippage(WithConstantEquityMinuteBarData,
|
class TestTestingSlippage(WithConstantEquityMinuteBarData,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
ASSET_FINDER_EQUITY_SYMBOLS = ('A',)
|
ASSET_FINDER_EQUITY_SYMBOLS = ('A',)
|
||||||
ASSET_FINDER_EQUITY_SIDS = (1,)
|
ASSET_FINDER_EQUITY_SIDS = (1,)
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ from catalyst.testing.fixtures import (
|
|||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
WithSimParams,
|
WithSimParams,
|
||||||
WithTradingEnvironment,
|
WithTradingEnvironment,
|
||||||
ZiplineTestCase,
|
CatalystTestCase,
|
||||||
)
|
)
|
||||||
from catalyst.utils import factory
|
from catalyst.utils import factory
|
||||||
from catalyst.testing.core import FakeDataPortal
|
from catalyst.testing.core import FakeDataPortal
|
||||||
@@ -53,7 +53,7 @@ class BeforeTradingAlgorithm(TradingAlgorithm):
|
|||||||
FREQUENCIES = {'daily': 0, 'minute': 1} # daily is less frequent than minute
|
FREQUENCIES = {'daily': 0, 'minute': 1} # daily is less frequent than minute
|
||||||
|
|
||||||
|
|
||||||
class TestTradeSimulation(WithTradingEnvironment, ZiplineTestCase):
|
class TestTradeSimulation(WithTradingEnvironment, CatalystTestCase):
|
||||||
|
|
||||||
def fake_minutely_benchmark(self, dt):
|
def fake_minutely_benchmark(self, dt):
|
||||||
return 0.01
|
return 0.01
|
||||||
@@ -115,7 +115,7 @@ class BeforeTradingStartsOnlyClock(object):
|
|||||||
|
|
||||||
class TestBeforeTradingStartSimulationDt(WithSimParams,
|
class TestBeforeTradingStartSimulationDt(WithSimParams,
|
||||||
WithDataPortal,
|
WithDataPortal,
|
||||||
ZiplineTestCase):
|
CatalystTestCase):
|
||||||
|
|
||||||
def test_bts_simulation_dt(self):
|
def test_bts_simulation_dt(self):
|
||||||
code = """
|
code = """
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from pandas import Timestamp
|
from pandas import Timestamp
|
||||||
from nose_parameterized import parameterized
|
from nose_parameterized import parameterized
|
||||||
|
|
||||||
from catalyst.testing import ZiplineTestCase
|
from catalyst.testing import CatalystTestCase
|
||||||
from catalyst.utils.calendars import get_calendar
|
from catalyst.utils.calendars import get_calendar
|
||||||
from catalyst.utils.date_utils import compute_date_range_chunks
|
from catalyst.utils.date_utils import compute_date_range_chunks
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ def T(s):
|
|||||||
return Timestamp(s, tz='UTC')
|
return Timestamp(s, tz='UTC')
|
||||||
|
|
||||||
|
|
||||||
class TestDateUtils(ZiplineTestCase):
|
class TestDateUtils(CatalystTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def init_class_fixtures(cls):
|
def init_class_fixtures(cls):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from catalyst.testing.fixtures import ZiplineTestCase
|
from catalyst.testing.fixtures import CatalystTestCase
|
||||||
from catalyst.testing.predicates import (
|
from catalyst.testing.predicates import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
assert_is,
|
assert_is,
|
||||||
@@ -31,7 +31,7 @@ class D(object):
|
|||||||
return 'D.delegate'
|
return 'D.delegate'
|
||||||
|
|
||||||
|
|
||||||
class ComposeTypesTestCase(ZiplineTestCase):
|
class ComposeTypesTestCase(CatalystTestCase):
|
||||||
|
|
||||||
def test_identity(self):
|
def test_identity(self):
|
||||||
assert_is(
|
assert_is(
|
||||||
@@ -67,7 +67,7 @@ class N(type):
|
|||||||
return super(N, mcls).__new__(mcls, name, bases, dict_)
|
return super(N, mcls).__new__(mcls, name, bases, dict_)
|
||||||
|
|
||||||
|
|
||||||
class WithMetaclassesTestCase(ZiplineTestCase):
|
class WithMetaclassesTestCase(CatalystTestCase):
|
||||||
def test_with_metaclasses_no_subclasses(self):
|
def test_with_metaclasses_no_subclasses(self):
|
||||||
class E(with_metaclasses((M, N))):
|
class E(with_metaclasses((M, N))):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Tests for catalyst/utils/pandas_utils.py
|
|||||||
"""
|
"""
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from catalyst.testing import parameter_space, ZiplineTestCase
|
from catalyst.testing import parameter_space, CatalystTestCase
|
||||||
from catalyst.testing.predicates import assert_equal
|
from catalyst.testing.predicates import assert_equal
|
||||||
from catalyst.utils.pandas_utils import (
|
from catalyst.utils.pandas_utils import (
|
||||||
categorical_df_concat,
|
categorical_df_concat,
|
||||||
@@ -11,7 +11,7 @@ from catalyst.utils.pandas_utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestNearestUnequalElements(ZiplineTestCase):
|
class TestNearestUnequalElements(CatalystTestCase):
|
||||||
|
|
||||||
@parameter_space(tz=['UTC', 'US/Eastern'], __fail_fast=True)
|
@parameter_space(tz=['UTC', 'US/Eastern'], __fail_fast=True)
|
||||||
def test_nearest_unequal_elements(self, tz):
|
def test_nearest_unequal_elements(self, tz):
|
||||||
@@ -86,7 +86,7 @@ class TestNearestUnequalElements(ZiplineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestCatDFConcat(ZiplineTestCase):
|
class TestCatDFConcat(CatalystTestCase):
|
||||||
|
|
||||||
def test_categorical_df_concat(self):
|
def test_categorical_df_concat(self):
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from catalyst.testing import ZiplineTestCase
|
from catalyst.testing import CatalystTestCase
|
||||||
from catalyst.utils.sharedoc import copydoc
|
from catalyst.utils.sharedoc import copydoc
|
||||||
|
|
||||||
|
|
||||||
class TestSharedoc(ZiplineTestCase):
|
class TestSharedoc(CatalystTestCase):
|
||||||
|
|
||||||
def test_copydoc(self):
|
def test_copydoc(self):
|
||||||
def original_docstring_function():
|
def original_docstring_function():
|
||||||
|
|||||||
Reference in New Issue
Block a user