mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-22 12:40:30 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49b6792399 | ||
|
|
6b1982274e | ||
|
|
bc58640a3a | ||
|
|
511af7946e | ||
|
|
dcdb3d9d7a | ||
|
|
5c77cfc68d | ||
|
|
11f8e36ff0 | ||
|
|
44e4e66f5c | ||
|
|
3c4c6c3dfd | ||
|
|
bebebc46dc | ||
|
|
403d7f9c29 | ||
|
|
09ad397ee6 | ||
|
|
e56e1f8e21 | ||
|
|
00f232e2d7 | ||
|
|
a820f66bdc | ||
|
|
82d318a1c0 | ||
|
|
97afbf781e | ||
|
|
43a5f8858b | ||
|
|
dc04cd8781 |
+1
-3
@@ -17,9 +17,7 @@ insights regarding a particular strategy's performance. Catalyst also supports
|
||||
live-trading of crypto-assets starting with three exchanges (Bitfinex, Bittrex,
|
||||
and Poloniex) with more being added over time. Catalyst empowers users to share
|
||||
and curate data and build profitable, data-driven investment strategies. Please
|
||||
visit `enigma.co <https://www.enigma.co>`_ to learn more about Catalyst, or
|
||||
refer to the `whitepaper <https://www.enigma.co/enigma_catalyst.pdf>`_ for
|
||||
further technical details.
|
||||
visit `enigma.co <https://www.enigma.co>`_ to learn more about Catalyst.
|
||||
|
||||
Catalyst builds on top of the well-established
|
||||
`Zipline <https://github.com/quantopian/zipline>`_ project. We did our best to
|
||||
|
||||
@@ -939,7 +939,7 @@ class TradingAlgorithm(object):
|
||||
The field to query. The options have the following meanings:
|
||||
arena : str
|
||||
The arena from the simulation parameters. This will normally
|
||||
be ``'backtest'`` but some systems may use this distinguish
|
||||
be ``backtest`` but some systems may use this distinguish
|
||||
live trading from backtesting.
|
||||
data_frequency : {'daily', 'minute'}
|
||||
data_frequency tells the algorithm if it is running with
|
||||
@@ -954,7 +954,7 @@ class TradingAlgorithm(object):
|
||||
The platform that the code is running on. By default this
|
||||
will be the string 'catalyst'. This can allow algorithms to
|
||||
know if they are running on the Quantopian platform instead.
|
||||
* : dict[str -> any]
|
||||
\* : dict[str -> any]
|
||||
Returns all of the fields in a dictionary.
|
||||
|
||||
Returns
|
||||
@@ -1032,7 +1032,7 @@ class TradingAlgorithm(object):
|
||||
argument is the name of the column in the preprocessed dataframe
|
||||
containing the symbols. This will be used along with the date
|
||||
information to map the sids in the asset finder.
|
||||
**kwargs
|
||||
\*\*kwargs
|
||||
Forwarded to :func:`pandas.read_csv`.
|
||||
|
||||
Returns
|
||||
@@ -1156,7 +1156,7 @@ class TradingAlgorithm(object):
|
||||
|
||||
Parameters
|
||||
----------
|
||||
**kwargs
|
||||
\*\*kwargs
|
||||
The names and values to record.
|
||||
|
||||
Notes
|
||||
@@ -1273,7 +1273,7 @@ class TradingAlgorithm(object):
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*args : iterable[str]
|
||||
\*args : iterable[str]
|
||||
The ticker symbols to lookup.
|
||||
|
||||
Returns
|
||||
|
||||
@@ -60,7 +60,7 @@ def _handle_data(context, data):
|
||||
rsi=rsi,
|
||||
)
|
||||
|
||||
orders = get_open_orders(context.asset)
|
||||
orders = context.blotter.open_orders
|
||||
if orders:
|
||||
log.info('skipping bar until all open orders execute')
|
||||
return
|
||||
@@ -146,11 +146,11 @@ if __name__ == '__main__':
|
||||
live = True
|
||||
if live:
|
||||
run_algorithm(
|
||||
capital_base=0.001,
|
||||
capital_base=1000,
|
||||
initialize=initialize,
|
||||
handle_data=handle_data,
|
||||
analyze=analyze,
|
||||
exchange_name='binance',
|
||||
exchange_name='bittrex',
|
||||
live=True,
|
||||
algo_namespace=algo_namespace,
|
||||
base_currency='btc',
|
||||
|
||||
@@ -20,8 +20,8 @@ def initialize(context):
|
||||
|
||||
def handle_data(context, data):
|
||||
# define the windows for the moving averages
|
||||
short_window = 50
|
||||
long_window = 200
|
||||
short_window = 2
|
||||
long_window = 2
|
||||
|
||||
# Skip as many bars as long_window to properly compute the average
|
||||
context.i += 1
|
||||
@@ -32,16 +32,18 @@ def handle_data(context, data):
|
||||
# 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,
|
||||
short_data = data.history(context.asset,
|
||||
'price',
|
||||
bar_count=short_window,
|
||||
frequency="1m",
|
||||
).mean()
|
||||
long_mavg = data.history(context.asset,
|
||||
frequency="1T",
|
||||
)
|
||||
short_mavg = short_data.mean()
|
||||
long_data = data.history(context.asset,
|
||||
'price',
|
||||
bar_count=long_window,
|
||||
frequency="1m",
|
||||
).mean()
|
||||
frequency="1T",
|
||||
)
|
||||
long_mavg = long_data.mean()
|
||||
|
||||
# Let's keep the price of our asset in a more handy variable
|
||||
price = data.current(context.asset, 'price')
|
||||
@@ -82,7 +84,6 @@ def handle_data(context, data):
|
||||
|
||||
|
||||
def analyze(context, perf):
|
||||
|
||||
# Get the base_currency that was passed as a parameter to the simulation
|
||||
exchange = list(context.exchanges.values())[0]
|
||||
base_currency = exchange.base_currency.upper()
|
||||
@@ -93,7 +94,7 @@ def analyze(context, perf):
|
||||
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))
|
||||
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)
|
||||
@@ -104,9 +105,9 @@ def analyze(context, perf):
|
||||
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))
|
||||
ax2.yaxis.set_ticks(np.arange(start, end, (end - start) / 5))
|
||||
|
||||
transaction_df = extract_transactions(perf)
|
||||
if not transaction_df.empty:
|
||||
@@ -136,28 +137,40 @@ def analyze(context, perf):
|
||||
ax3.legend_.remove()
|
||||
ax3.set_ylabel('Percent Change')
|
||||
start, end = ax3.get_ylim()
|
||||
ax3.yaxis.set_ticks(np.arange(start, end, (end-start)/5))
|
||||
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))
|
||||
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),
|
||||
)
|
||||
capital_base=1000,
|
||||
data_frequency='minute',
|
||||
initialize=initialize,
|
||||
handle_data=handle_data,
|
||||
analyze=analyze,
|
||||
exchange_name='bitfinex',
|
||||
algo_namespace=NAMESPACE,
|
||||
base_currency='usd',
|
||||
simulate_orders=True,
|
||||
live=True,
|
||||
)
|
||||
# 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),
|
||||
# )
|
||||
|
||||
@@ -425,15 +425,12 @@ class CCXT(Exchange):
|
||||
'Please provide either start_dt or end_dt, not both.'
|
||||
)
|
||||
|
||||
elif end_dt is not None:
|
||||
# Make sure that end_dt really wants data in the past
|
||||
# if it's close to now, we skip the 'since' parameters to
|
||||
# lower the probability of error
|
||||
bars_to_now = pd.date_range(
|
||||
end_dt, pd.Timestamp.utcnow(), freq=freq
|
||||
)
|
||||
# See: https://github.com/ccxt/ccxt/issues/1360
|
||||
if len(bars_to_now) > 1 or self.name in ['poloniex']:
|
||||
if start_dt is None:
|
||||
# TODO: determine why binance is failing
|
||||
if end_dt is None and self.name not in ['binance']:
|
||||
end_dt = pd.Timestamp.utcnow()
|
||||
|
||||
if end_dt is not None:
|
||||
dt_range = get_periods_range(
|
||||
end_dt=end_dt,
|
||||
periods=bar_count,
|
||||
@@ -441,10 +438,13 @@ class CCXT(Exchange):
|
||||
)
|
||||
start_dt = dt_range[0]
|
||||
|
||||
since = None
|
||||
if start_dt is not None:
|
||||
# Convert out start date to a UNIX timestamp, then translate to
|
||||
# milliseconds
|
||||
delta = start_dt - get_epoch()
|
||||
since = int(delta.total_seconds()) * 1000
|
||||
else:
|
||||
since = None
|
||||
|
||||
candles = dict()
|
||||
for index, asset in enumerate(assets):
|
||||
|
||||
@@ -391,8 +391,6 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
||||
log.warn("Can't initialize signal handler inside another thread."
|
||||
"Exit should be handled by the user.")
|
||||
|
||||
log.info('initialized trading algorithm in live mode')
|
||||
|
||||
def interrupt_algorithm(self):
|
||||
self.is_running = False
|
||||
|
||||
@@ -874,6 +872,13 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_open_orders(self, asset=None):
|
||||
if self.simulate_orders:
|
||||
raise ValueError(
|
||||
'The get_open_orders() method only works in live mode. '
|
||||
'The purpose is to list open orders on the exchange '
|
||||
'regardless who placed them. To list the open orders of '
|
||||
'this algo, use `context.blotter.open_orders`.'
|
||||
)
|
||||
if asset:
|
||||
exchange = self.exchanges[asset.exchange]
|
||||
return exchange.get_open_orders(asset)
|
||||
@@ -907,6 +912,7 @@ class ExchangeTradingAlgorithmLive(ExchangeTradingAlgorithmBase):
|
||||
If an asset is passed then this will return a list of the open
|
||||
orders for this asset.
|
||||
"""
|
||||
# TODO: should this be a shortcut to the open orders in the blotter?
|
||||
return retry(
|
||||
action=self._get_open_orders,
|
||||
attempts=self.attempts['get_open_orders_attempts'],
|
||||
|
||||
@@ -458,7 +458,7 @@ class ExchangeBundle:
|
||||
last_entry = None
|
||||
|
||||
if start is None or \
|
||||
(earliest_trade is not None and earliest_trade > start):
|
||||
(earliest_trade is not None and earliest_trade > start):
|
||||
start = earliest_trade
|
||||
|
||||
if last_entry is not None and (end is None or end > last_entry):
|
||||
@@ -600,14 +600,14 @@ class ExchangeBundle:
|
||||
if show_breakdown:
|
||||
for asset in chunks:
|
||||
with maybe_show_progress(
|
||||
chunks[asset],
|
||||
show_progress,
|
||||
label='Ingesting {frequency} price data for '
|
||||
'{symbol} on {exchange}'.format(
|
||||
exchange=self.exchange_name,
|
||||
frequency=data_frequency,
|
||||
symbol=asset.symbol
|
||||
)) as it:
|
||||
chunks[asset],
|
||||
show_progress,
|
||||
label='Ingesting {frequency} price data for '
|
||||
'{symbol} on {exchange}'.format(
|
||||
exchange=self.exchange_name,
|
||||
frequency=data_frequency,
|
||||
symbol=asset.symbol
|
||||
)) as it:
|
||||
for chunk in it:
|
||||
problems += self.ingest_ctable(
|
||||
asset=chunk['asset'],
|
||||
@@ -625,13 +625,13 @@ class ExchangeBundle:
|
||||
key=lambda chunk: pd.to_datetime(chunk['period'])
|
||||
)
|
||||
with maybe_show_progress(
|
||||
all_chunks,
|
||||
show_progress,
|
||||
label='Ingesting {frequency} price data on '
|
||||
'{exchange}'.format(
|
||||
exchange=self.exchange_name,
|
||||
frequency=data_frequency,
|
||||
)) as it:
|
||||
all_chunks,
|
||||
show_progress,
|
||||
label='Ingesting {frequency} price data on '
|
||||
'{exchange}'.format(
|
||||
exchange=self.exchange_name,
|
||||
frequency=data_frequency,
|
||||
)) as it:
|
||||
for chunk in it:
|
||||
problems += self.ingest_ctable(
|
||||
asset=chunk['asset'],
|
||||
@@ -830,7 +830,6 @@ class ExchangeBundle:
|
||||
field,
|
||||
data_frequency,
|
||||
algo_end_dt=None,
|
||||
trailing_bar_count=None,
|
||||
force_auto_ingest=False
|
||||
):
|
||||
"""
|
||||
@@ -858,7 +857,6 @@ class ExchangeBundle:
|
||||
bar_count=bar_count,
|
||||
field=field,
|
||||
data_frequency=data_frequency,
|
||||
trailing_bar_count=trailing_bar_count,
|
||||
)
|
||||
return pd.DataFrame(series)
|
||||
|
||||
@@ -887,7 +885,6 @@ class ExchangeBundle:
|
||||
field=field,
|
||||
data_frequency=data_frequency,
|
||||
reset_reader=True,
|
||||
trailing_bar_count=trailing_bar_count,
|
||||
)
|
||||
return series
|
||||
|
||||
@@ -898,7 +895,6 @@ class ExchangeBundle:
|
||||
bar_count=bar_count,
|
||||
field=field,
|
||||
data_frequency=data_frequency,
|
||||
trailing_bar_count=trailing_bar_count,
|
||||
)
|
||||
return pd.DataFrame(series)
|
||||
|
||||
@@ -962,12 +958,7 @@ class ExchangeBundle:
|
||||
bar_count,
|
||||
field,
|
||||
data_frequency,
|
||||
trailing_bar_count=None,
|
||||
reset_reader=False):
|
||||
if trailing_bar_count:
|
||||
delta = get_delta(trailing_bar_count, data_frequency)
|
||||
end_dt += delta
|
||||
|
||||
start_dt = get_start_dt(end_dt, bar_count, data_frequency, False)
|
||||
start_dt, _ = self.get_adj_dates(
|
||||
start_dt, end_dt, assets, data_frequency
|
||||
|
||||
@@ -298,7 +298,6 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase):
|
||||
frequency, data_frequency
|
||||
)
|
||||
adj_bar_count = candle_size * bar_count
|
||||
trailing_bar_count = candle_size - 1
|
||||
|
||||
if data_frequency == 'minute' and adj_data_frequency == 'daily':
|
||||
end_dt = end_dt.floor('1D')
|
||||
@@ -310,7 +309,6 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase):
|
||||
field=field,
|
||||
data_frequency=adj_data_frequency,
|
||||
algo_end_dt=self._last_available_session,
|
||||
trailing_bar_count=trailing_bar_count,
|
||||
)
|
||||
|
||||
df = resample_history_df(pd.DataFrame(series), freq, field)
|
||||
|
||||
@@ -540,7 +540,7 @@ def resample_history_df(df, freq, field):
|
||||
else:
|
||||
raise ValueError('Invalid field.')
|
||||
|
||||
resampled_df = df.resample(freq).agg(agg)
|
||||
resampled_df = df.resample(freq, closed='left', label='left').agg(agg)
|
||||
return resampled_df
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# !/usr/bin/env python2
|
||||
|
||||
import sys
|
||||
import os
|
||||
import pandas as pd
|
||||
import signal
|
||||
# import talib
|
||||
|
||||
from logbook import Logger
|
||||
|
||||
from catalyst import run_algorithm
|
||||
from catalyst.api import (
|
||||
symbol,
|
||||
record,
|
||||
order,
|
||||
order_target,
|
||||
order_target_percent,
|
||||
get_open_orders
|
||||
)
|
||||
from catalyst.finance import commission
|
||||
|
||||
|
||||
# from base.telegrambot import TelegramBot
|
||||
|
||||
|
||||
class GracefulKiller:
|
||||
# Source: https://stackoverflow.com/a/31464349
|
||||
def __init__(self, context):
|
||||
self.kill_now = False
|
||||
self.signal = 0
|
||||
self.context = context
|
||||
signal.signal(signal.SIGINT, self.exit_gracefully)
|
||||
|
||||
def exit_gracefully(self, signum, frame):
|
||||
self.kill_now = True
|
||||
self.signal = signum
|
||||
if hasattr(self.context,
|
||||
'telegram_bot') and self.context.telegram_bot is not None:
|
||||
self.context.telegram_bot.updater.stop()
|
||||
sys.exit(0)
|
||||
|
||||
def exit(self):
|
||||
return self.kill_now
|
||||
|
||||
|
||||
class SimulationParameters:
|
||||
MODE = 'paper'
|
||||
CAPITAL_BASE = 1000
|
||||
"""
|
||||
Capital base used on this simulation
|
||||
"""
|
||||
|
||||
DATA_FREQUECY = 'minute'
|
||||
|
||||
EXCHANGE_NAME = 'bitfinex'
|
||||
# EXCHANGE_NAME = 'binance'
|
||||
"""
|
||||
Exchange used on this simulation
|
||||
"""
|
||||
|
||||
DATA_DIR = '/home/av/Dropbox/simulations/data'
|
||||
ALGO_NAMESPACE = os.path.basename(__file__).split('.')[0]
|
||||
ALGO_NAMESPACE_IMAGE = '{}/{}/{}.png'.format(DATA_DIR, 'images',
|
||||
ALGO_NAMESPACE)
|
||||
ALGO_NAMESPACE_RESULTS_TABLE = '{}/{}/{}.csv'.format(DATA_DIR, 'tables',
|
||||
ALGO_NAMESPACE + '_results')
|
||||
ALGO_NAMESPACE_TRANSACTIONS_TABLE = '{}/{}/{}.csv'.format(DATA_DIR,
|
||||
'tables',
|
||||
ALGO_NAMESPACE + '_transactions')
|
||||
BASE_CURRENCY = 'usd'
|
||||
# BASE_CURRENCY = 'usdt'
|
||||
|
||||
# SHORT PERIOD
|
||||
START_DATE = '2017-09-07'
|
||||
"""
|
||||
Start date used on this simulation
|
||||
"""
|
||||
END_DATE = '2017-12-12'
|
||||
"""
|
||||
End date used on this simulation
|
||||
"""
|
||||
|
||||
SKIP_FIRST_CANDLES = 0
|
||||
|
||||
# CANDLES_SAMPLE_RATE = 60
|
||||
# CANDLES_SAMPLE_RATE = 30
|
||||
CANDLES_SAMPLE_RATE = 1
|
||||
"""
|
||||
Candle interval used on this simulation (in minutes)
|
||||
"""
|
||||
|
||||
# http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
|
||||
# 30 minute interval ohlcv data (the standard data required for candlestick or
|
||||
# indicators/signals)
|
||||
# 30T means 30 minutes re-sampling of one minute data.
|
||||
# CANDLES_FREQUENCY = '60T'
|
||||
# CANDLES_FREQUENCY = '30T'
|
||||
CANDLES_FREQUENCY = '1T'
|
||||
CANDLES_BUFFER_SIZE = 48
|
||||
COIN_PAIR = 'btc_usd'
|
||||
# COIN_PAIR = 'btc_usdt'
|
||||
"""
|
||||
Coin pair used on this simulation
|
||||
"""
|
||||
|
||||
# TRANSACTIONS
|
||||
COMMISSION_FEE = 0.0030
|
||||
BUY_MIN_AMOUNT = 5 # i.e: USD
|
||||
SELL_MIN_AMOUNT = 0.001 # i.e: USD
|
||||
BUY_SELL_PERCENTAGE = 1 # 0.50
|
||||
BUY_PERCENTAGE = BUY_SELL_PERCENTAGE
|
||||
SELL_PERCENTAGE = BUY_SELL_PERCENTAGE
|
||||
|
||||
BASE_PRICE = 'close'
|
||||
"""
|
||||
Base price used (close / Heiken Ashi)
|
||||
"""
|
||||
|
||||
|
||||
log = None
|
||||
parameters = None
|
||||
|
||||
|
||||
def print_facts(context):
|
||||
context.log.info("""
|
||||
Index: {}
|
||||
Date: {}
|
||||
Candle:
|
||||
O: {}
|
||||
H: {}
|
||||
L: {}
|
||||
C: {}
|
||||
V: {}
|
||||
Metrics:
|
||||
...
|
||||
Portfolio:
|
||||
Base price: {}
|
||||
Base coin (coin2/usd): {}
|
||||
Amount (coin1/btc): {}
|
||||
""".format(
|
||||
# Facts
|
||||
context.i,
|
||||
context.curr_minute,
|
||||
context.candles_open[-1],
|
||||
context.candles_high[-1],
|
||||
context.candles_low[-1],
|
||||
context.candles_close[-1],
|
||||
context.candles_volume[-1],
|
||||
# Metrics
|
||||
# ...
|
||||
# Portfolio
|
||||
context.curr_base_price,
|
||||
context.portfolio.cash,
|
||||
context.portfolio.positions[context.coin_pair].amount,
|
||||
))
|
||||
|
||||
|
||||
def print_facts_telegram(context):
|
||||
price = context.curr_base_price
|
||||
amount = context.portfolio.positions[context.coin_pair].amount
|
||||
pnl = context.portfolio.pnl
|
||||
capital_used = context.portfolio.capital_used
|
||||
portfolio_value = context.portfolio.portfolio_value
|
||||
portfolio_returns = context.portfolio.returns
|
||||
starting_cash = context.portfolio.starting_cash
|
||||
cash = context.portfolio.cash
|
||||
|
||||
msg = """
|
||||
Status...
|
||||
Price: {}
|
||||
Starting cash: {}
|
||||
Cash: {}
|
||||
Capital used: {}
|
||||
Amount: {}
|
||||
Portfolio value: {}
|
||||
Returns: {}
|
||||
PnL: {}
|
||||
""".format(
|
||||
price,
|
||||
starting_cash,
|
||||
cash,
|
||||
capital_used,
|
||||
amount,
|
||||
portfolio_value,
|
||||
portfolio_returns,
|
||||
pnl,
|
||||
)
|
||||
if hasattr(context, 'telegram_bot') and context.telegram_bot is not None:
|
||||
context.telegram_bot.msg(msg)
|
||||
|
||||
|
||||
def default_initialize(context):
|
||||
# FIXME: set_benchmark
|
||||
# set_benchmark(symbol(context.parameters.COIN_PAIR))
|
||||
|
||||
context.coin_pair = symbol(context.parameters.COIN_PAIR)
|
||||
context.base_price = None
|
||||
context.current_day = None
|
||||
context.counter = -1
|
||||
context.i = 0
|
||||
|
||||
context.candles_sample_rate = context.parameters.CANDLES_SAMPLE_RATE
|
||||
context.candles_frequency = context.parameters.CANDLES_FREQUENCY
|
||||
context.candles_buffer_size = context.parameters.CANDLES_BUFFER_SIZE
|
||||
context.set_commission(
|
||||
commission.PerShare(cost=context.parameters.COMMISSION_FEE))
|
||||
|
||||
|
||||
def default_handle_data(context, data):
|
||||
context.curr_minute = data.current_dt
|
||||
context.counter += 1
|
||||
|
||||
if context.candles_sample_rate == 1:
|
||||
context.i += 1
|
||||
elif context.counter % context.candles_sample_rate != 0:
|
||||
context.i += 1
|
||||
return
|
||||
|
||||
if context.i < context.parameters.SKIP_FIRST_CANDLES:
|
||||
return
|
||||
|
||||
context.candles_open = data.history(
|
||||
context.coin_pair,
|
||||
'open',
|
||||
bar_count=context.candles_buffer_size,
|
||||
frequency=context.candles_frequency)
|
||||
context.candles_high = data.history(
|
||||
context.coin_pair,
|
||||
'high',
|
||||
bar_count=context.candles_buffer_size,
|
||||
frequency=context.candles_frequency)
|
||||
context.candles_low = data.history(
|
||||
context.coin_pair,
|
||||
'low',
|
||||
bar_count=context.candles_buffer_size,
|
||||
frequency=context.candles_frequency)
|
||||
context.candles_close = data.history(
|
||||
context.coin_pair,
|
||||
'price',
|
||||
bar_count=context.candles_buffer_size,
|
||||
frequency=context.candles_frequency)
|
||||
context.candles_volume = data.history(
|
||||
context.coin_pair,
|
||||
'volume',
|
||||
bar_count=context.candles_buffer_size,
|
||||
frequency=context.candles_frequency)
|
||||
|
||||
# FIXME: Here is the error!
|
||||
# The candles_close frame shows more or less always a value of 94, while
|
||||
# bitcoin price is very different from that
|
||||
print(context.candles_close)
|
||||
|
||||
context.base_prices = context.candles_close
|
||||
cash = context.portfolio.cash
|
||||
amount = context.portfolio.positions[context.coin_pair].amount
|
||||
price = data.current(context.coin_pair, 'price')
|
||||
order_id = None
|
||||
context.last_base_price = context.base_prices[-2]
|
||||
context.curr_base_price = context.base_prices[-1]
|
||||
|
||||
# TA calculations
|
||||
# ...
|
||||
|
||||
# Sanity checks
|
||||
# assert cash >= 0
|
||||
if cash < 0:
|
||||
import ipdb;
|
||||
ipdb.set_trace() # BREAKPOINT
|
||||
|
||||
print_facts(context)
|
||||
print_facts_telegram(context)
|
||||
|
||||
# Order management
|
||||
net_shares = 0
|
||||
if context.counter == 2:
|
||||
brute_shares = (cash / price) * context.parameters.BUY_PERCENTAGE
|
||||
share_commission_fee = brute_shares * context.parameters.COMMISSION_FEE
|
||||
net_shares = brute_shares - share_commission_fee
|
||||
buy_order_id = order(context.coin_pair, net_shares)
|
||||
|
||||
if context.counter == 3:
|
||||
brute_shares = amount * context.parameters.SELL_PERCENTAGE
|
||||
share_commission_fee = brute_shares * context.parameters.COMMISSION_FEE
|
||||
net_shares = -(brute_shares - share_commission_fee)
|
||||
sell_order_id = order(context.coin_pair, net_shares)
|
||||
|
||||
# Record
|
||||
record(
|
||||
price=price,
|
||||
foo='bar',
|
||||
# volume=current['volume'],
|
||||
# price_change=price_change,
|
||||
# Metrics
|
||||
cash=cash,
|
||||
# buy=context.buy,
|
||||
# sell=context.sell
|
||||
)
|
||||
|
||||
|
||||
def default_analyze(context=None, perf=None):
|
||||
pass
|
||||
|
||||
|
||||
def initialize(context):
|
||||
global log
|
||||
context.parameters = parameters
|
||||
context.log = Logger(context.parameters.ALGO_NAMESPACE)
|
||||
log = context.log
|
||||
default_initialize(context)
|
||||
context.killer = GracefulKiller(context)
|
||||
context.telegram_bot = None
|
||||
|
||||
# TELEGRAM_TOKEN='token'
|
||||
# context.telegram_bot = TelegramBot()
|
||||
# context.telegram_bot.initialize(TELEGRAM_TOKEN, context)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Parameters:
|
||||
parameters = SimulationParameters()
|
||||
start_date = pd.to_datetime(parameters.START_DATE, utc=True)
|
||||
end_date = pd.to_datetime(parameters.END_DATE, utc=True)
|
||||
|
||||
if parameters.MODE == 'backtest':
|
||||
results = run_algorithm(
|
||||
capital_base=parameters.CAPITAL_BASE,
|
||||
data_frequency=parameters.DATA_FREQUECY,
|
||||
initialize=initialize,
|
||||
handle_data=default_handle_data,
|
||||
analyze=default_analyze,
|
||||
exchange_name=parameters.EXCHANGE_NAME,
|
||||
algo_namespace=parameters.ALGO_NAMESPACE,
|
||||
base_currency=parameters.BASE_CURRENCY,
|
||||
start=start_date,
|
||||
end=end_date,
|
||||
live=False,
|
||||
live_graph=False
|
||||
)
|
||||
|
||||
returns_daily = results
|
||||
results.to_csv('{}'.format(parameters.ALGO_NAMESPACE_RESULTS_TABLE))
|
||||
|
||||
# returns_daily = returns_minutely.add(1).groupby(pd.TimeGrouper('24H')).prod().add(-1)
|
||||
|
||||
# FIXME: pyfolio integration
|
||||
# pf_data = pyfolio.utils.extract_rets_pos_txn_from_zipline(results)
|
||||
# pf_data = pyfolio.utils.extract_rets_pos_txn_from_zipline(results[:'2017-01-01'])
|
||||
# pyfolio.create_full_tear_sheet(*pf_data)
|
||||
|
||||
elif parameters.MODE == 'paper':
|
||||
results = run_algorithm(
|
||||
capital_base=parameters.CAPITAL_BASE,
|
||||
data_frequency=parameters.DATA_FREQUECY,
|
||||
initialize=initialize,
|
||||
handle_data=default_handle_data,
|
||||
analyze=default_analyze,
|
||||
exchange_name=parameters.EXCHANGE_NAME,
|
||||
algo_namespace=parameters.ALGO_NAMESPACE,
|
||||
base_currency=parameters.BASE_CURRENCY,
|
||||
live=True,
|
||||
simulate_orders=True,
|
||||
live_graph=False
|
||||
)
|
||||
|
||||
elif parameters.MODE == 'live':
|
||||
results = run_algorithm(
|
||||
initialize=initialize,
|
||||
handle_data=default_handle_data,
|
||||
analyze=default_analyze,
|
||||
exchange_name=parameters.EXCHANGE_NAME,
|
||||
algo_namespace=parameters.ALGO_NAMESPACE,
|
||||
base_currency=parameters.BASE_CURRENCY,
|
||||
live=True,
|
||||
live_graph=True
|
||||
)
|
||||
@@ -55,6 +55,7 @@ class _RunAlgoError(click.ClickException, ValueError):
|
||||
----------
|
||||
pyfunc_msg : str
|
||||
The message that will be shown when called as a python function.
|
||||
|
||||
cmdline_msg : str
|
||||
The message that will be shown on the command line.
|
||||
"""
|
||||
@@ -416,7 +417,8 @@ def run_algorithm(initialize,
|
||||
auth_aliases=None,
|
||||
stats_output=None,
|
||||
output=os.devnull):
|
||||
"""Run a trading algorithm.
|
||||
"""
|
||||
Run a trading algorithm.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -458,7 +460,7 @@ def run_algorithm(initialize,
|
||||
This argument is mutually exclusive with ``data``.
|
||||
default_extension : bool, optional
|
||||
Should the default catalyst extension be loaded. This is found at
|
||||
``$ZIPLINE_ROOT/extension.py``
|
||||
``$CATALYST_ROOT/extension.py``
|
||||
extensions : iterable[str], optional
|
||||
The names of any other extensions to load. Each element may either be
|
||||
a dotted module path like ``a.b.c`` or a path to a python file ending
|
||||
@@ -469,12 +471,8 @@ def run_algorithm(initialize,
|
||||
environ : mapping[str -> str], optional
|
||||
The os environment to use. Many extensions use this to get parameters.
|
||||
This defaults to ``os.environ``.
|
||||
live: execute live trading
|
||||
exchange_conn: The exchange connection parameters
|
||||
|
||||
Supported Exchanges
|
||||
-------------------
|
||||
bitfinex
|
||||
live : bool, optional
|
||||
Execute algorithm in live trading mode.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
+173
-179
@@ -4,7 +4,7 @@ API Reference
|
||||
Running a Backtest
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autofunction:: zipline.run_algorithm(...)
|
||||
.. autofunction:: catalyst.run_algorithm(...)
|
||||
|
||||
Algorithm API
|
||||
~~~~~~~~~~~~~
|
||||
@@ -18,341 +18,335 @@ currently-executing :class:`~zipline.algorithm.TradingAlgorithm` instance.
|
||||
Data Object
|
||||
```````````
|
||||
|
||||
.. autoclass:: zipline.protocol.BarData
|
||||
.. autoclass:: catalyst.protocol.BarData
|
||||
:members:
|
||||
|
||||
Scheduling Functions
|
||||
````````````````````
|
||||
|
||||
.. autofunction:: zipline.api.schedule_function
|
||||
.. autofunction:: catalyst.api.schedule_function
|
||||
|
||||
.. autoclass:: zipline.api.date_rules
|
||||
.. autoclass:: catalyst.api.date_rules
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: zipline.api.time_rules
|
||||
.. autoclass:: catalyst.api.time_rules
|
||||
:members:
|
||||
|
||||
Orders
|
||||
``````
|
||||
|
||||
.. autofunction:: zipline.api.order
|
||||
.. autofunction:: catalyst.api.order
|
||||
|
||||
.. autofunction:: zipline.api.order_value
|
||||
.. autofunction:: catalyst.api.order_value
|
||||
|
||||
.. autofunction:: zipline.api.order_percent
|
||||
.. autofunction:: catalyst.api.order_percent
|
||||
|
||||
.. autofunction:: zipline.api.order_target
|
||||
.. autofunction:: catalyst.api.order_target
|
||||
|
||||
.. autofunction:: zipline.api.order_target_value
|
||||
.. autofunction:: catalyst.api.order_target_value
|
||||
|
||||
.. autofunction:: zipline.api.order_target_percent
|
||||
.. autofunction:: catalyst.api.order_target_percent
|
||||
|
||||
.. autoclass:: zipline.finance.execution.ExecutionStyle
|
||||
.. autoclass:: catalyst.finance.execution.ExecutionStyle
|
||||
:members:
|
||||
|
||||
.. autoclass:: zipline.finance.execution.MarketOrder
|
||||
.. autoclass:: catalyst.finance.execution.MarketOrder
|
||||
|
||||
.. autoclass:: zipline.finance.execution.LimitOrder
|
||||
.. autoclass:: catalyst.finance.execution.LimitOrder
|
||||
|
||||
.. autoclass:: zipline.finance.execution.StopOrder
|
||||
.. autoclass:: catalyst.finance.execution.StopOrder
|
||||
|
||||
.. autoclass:: zipline.finance.execution.StopLimitOrder
|
||||
.. autoclass:: catalyst.finance.execution.StopLimitOrder
|
||||
|
||||
.. autofunction:: zipline.api.get_order
|
||||
.. autofunction:: catalyst.api.get_order
|
||||
|
||||
.. autofunction:: zipline.api.get_open_orders
|
||||
.. autofunction:: catalyst.api.get_open_orders
|
||||
|
||||
.. autofunction:: zipline.api.cancel_order
|
||||
.. autofunction:: catalyst.api.cancel_order
|
||||
|
||||
Order Cancellation Policies
|
||||
'''''''''''''''''''''''''''
|
||||
|
||||
.. autofunction:: zipline.api.set_cancel_policy
|
||||
.. autofunction:: catalyst.api.set_cancel_policy
|
||||
|
||||
.. autoclass:: zipline.finance.cancel_policy.CancelPolicy
|
||||
.. autoclass:: catalyst.finance.cancel_policy.CancelPolicy
|
||||
:members:
|
||||
|
||||
.. autofunction:: zipline.api.EODCancel
|
||||
.. autofunction:: catalyst.api.EODCancel
|
||||
|
||||
.. autofunction:: zipline.api.NeverCancel
|
||||
.. autofunction:: catalyst.api.NeverCancel
|
||||
|
||||
|
||||
Assets
|
||||
``````
|
||||
|
||||
.. autofunction:: zipline.api.symbol
|
||||
.. autofunction:: catalyst.api.symbol
|
||||
|
||||
.. autofunction:: zipline.api.symbols
|
||||
.. autofunction:: catalyst.api.symbols
|
||||
|
||||
.. autofunction:: zipline.api.future_symbol
|
||||
.. autofunction:: catalyst.api.set_symbol_lookup_date
|
||||
|
||||
.. autofunction:: zipline.api.set_symbol_lookup_date
|
||||
|
||||
.. autofunction:: zipline.api.sid
|
||||
.. autofunction:: catalyst.api.sid
|
||||
|
||||
|
||||
Trading Controls
|
||||
````````````````
|
||||
|
||||
Zipline provides trading controls to help ensure that the algorithm is
|
||||
zipline provides trading controls to help ensure that the algorithm is
|
||||
performing as expected. The functions help protect the algorithm from certian
|
||||
bugs that could cause undesirable behavior when trading with real money.
|
||||
|
||||
.. autofunction:: zipline.api.set_do_not_order_list
|
||||
.. autofunction:: catalyst.api.set_do_not_order_list
|
||||
|
||||
.. autofunction:: zipline.api.set_long_only
|
||||
.. autofunction:: catalyst.api.set_long_only
|
||||
|
||||
.. autofunction:: zipline.api.set_max_leverage
|
||||
.. autofunction:: catalyst.api.set_max_leverage
|
||||
|
||||
.. autofunction:: zipline.api.set_max_order_count
|
||||
.. autofunction:: catalyst.api.set_max_order_count
|
||||
|
||||
.. autofunction:: zipline.api.set_max_order_size
|
||||
.. autofunction:: catalyst.api.set_max_order_size
|
||||
|
||||
.. autofunction:: zipline.api.set_max_position_size
|
||||
.. autofunction:: catalyst.api.set_max_position_size
|
||||
|
||||
|
||||
Simulation Parameters
|
||||
`````````````````````
|
||||
|
||||
.. autofunction:: zipline.api.set_benchmark
|
||||
.. autofunction:: catalyst.api.set_benchmark
|
||||
|
||||
Commission Models
|
||||
'''''''''''''''''
|
||||
|
||||
.. autofunction:: zipline.api.set_commission
|
||||
.. autofunction:: catalyst.api.set_commission
|
||||
|
||||
.. autoclass:: zipline.finance.commission.CommissionModel
|
||||
.. autoclass:: catalyst.finance.commission.CommissionModel
|
||||
:members:
|
||||
|
||||
.. autoclass:: zipline.finance.commission.PerShare
|
||||
.. autoclass:: catalyst.finance.commission.PerShare
|
||||
|
||||
.. autoclass:: zipline.finance.commission.PerTrade
|
||||
.. autoclass:: catalyst.finance.commission.PerTrade
|
||||
|
||||
.. autoclass:: zipline.finance.commission.PerDollar
|
||||
.. autoclass:: catalyst.finance.commission.PerDollar
|
||||
|
||||
Slippage Models
|
||||
'''''''''''''''
|
||||
|
||||
.. autofunction:: zipline.api.set_slippage
|
||||
.. autofunction:: catalyst.api.set_slippage
|
||||
|
||||
.. autoclass:: zipline.finance.slippage.SlippageModel
|
||||
.. autoclass:: catalyst.finance.slippage.SlippageModel
|
||||
:members:
|
||||
|
||||
.. autoclass:: zipline.finance.slippage.FixedSlippage
|
||||
.. autoclass:: catalyst.finance.slippage.FixedSlippage
|
||||
|
||||
.. autoclass:: zipline.finance.slippage.VolumeShareSlippage
|
||||
.. autoclass:: catalyst.finance.slippage.VolumeShareSlippage
|
||||
|
||||
Pipeline
|
||||
````````
|
||||
|
||||
For more information, see :ref:`pipeline-api`
|
||||
Not supported yet.
|
||||
|
||||
.. autofunction:: zipline.api.attach_pipeline
|
||||
.. For more information, see :ref:`pipeline-api`
|
||||
|
||||
.. autofunction:: zipline.api.pipeline_output
|
||||
.. .. autofunction:: catalyst.api.attach_pipeline
|
||||
|
||||
.. .. autofunction:: catalyst.api.pipeline_output
|
||||
|
||||
|
||||
Miscellaneous
|
||||
`````````````
|
||||
|
||||
.. autofunction:: zipline.api.record
|
||||
.. autofunction:: catalyst.api.record
|
||||
|
||||
.. autofunction:: zipline.api.get_environment
|
||||
.. autofunction:: catalyst.api.get_environment
|
||||
|
||||
.. autofunction:: zipline.api.fetch_csv
|
||||
.. autofunction:: catalyst.api.fetch_csv
|
||||
|
||||
|
||||
.. _pipeline-api:
|
||||
|
||||
Pipeline API
|
||||
~~~~~~~~~~~~
|
||||
.. Pipeline API
|
||||
.. ~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: zipline.pipeline.Pipeline
|
||||
:members:
|
||||
:member-order: groupwise
|
||||
.. .. autoclass:: zipline.pipeline.Pipeline
|
||||
.. :members:
|
||||
.. :member-order: groupwise
|
||||
|
||||
.. autoclass:: zipline.pipeline.CustomFactor
|
||||
:members:
|
||||
:member-order: groupwise
|
||||
.. .. autoclass:: zipline.pipeline.CustomFactor
|
||||
.. :members:
|
||||
.. :member-order: groupwise
|
||||
|
||||
.. autoclass:: zipline.pipeline.filters.Filter
|
||||
:members: __and__, __or__
|
||||
:exclude-members: dtype
|
||||
.. .. autoclass:: zipline.pipeline.filters.Filter
|
||||
.. :members: __and__, __or__
|
||||
.. :exclude-members: dtype
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.Factor
|
||||
:members: bottom, deciles, demean, linear_regression, pearsonr,
|
||||
percentile_between, quantiles, quartiles, quintiles, rank,
|
||||
spearmanr, top, winsorize, zscore, isnan, notnan, isfinite, eq,
|
||||
__add__, __sub__, __mul__, __div__, __mod__, __pow__, __lt__,
|
||||
__le__, __ne__, __ge__, __gt__
|
||||
:exclude-members: dtype
|
||||
:member-order: bysource
|
||||
.. .. autoclass:: zipline.pipeline.factors.Factor
|
||||
.. :members: bottom, deciles, demean, linear_regression, pearsonr,
|
||||
.. percentile_between, quantiles, quartiles, quintiles, rank,
|
||||
.. spearmanr, top, winsorize, zscore, isnan, notnan, isfinite, eq,
|
||||
.. \__add__, \__sub__, \__mul__, \__div__, \__mod__, \__pow__,
|
||||
.. \__lt__, \__le__, \__ne__, \__ge__, \__gt__
|
||||
.. :exclude-members: dtype
|
||||
.. :member-order: bysource
|
||||
|
||||
.. autoclass:: zipline.pipeline.term.Term
|
||||
:members:
|
||||
:exclude-members: compute_extra_rows, dependencies, inputs, mask, windowed
|
||||
.. .. autoclass:: zipline.pipeline.term.Term
|
||||
.. :members:
|
||||
.. :exclude-members: compute_extra_rows, dependencies, inputs, mask, windowed
|
||||
|
||||
.. autoclass:: zipline.pipeline.data.USEquityPricing
|
||||
:members: open, high, low, close, volume
|
||||
:undoc-members:
|
||||
.. .. autoclass:: zipline.pipeline.data.USEquityPricing
|
||||
.. :members: open, high, low, close, volume
|
||||
.. :undoc-members:
|
||||
|
||||
Built-in Factors
|
||||
````````````````
|
||||
.. Built-in Factors
|
||||
.. ````````````````
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.AverageDollarVolume
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.AverageDollarVolume
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.BollingerBands
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.BollingerBands
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.BusinessDaysSincePreviousEvent
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.BusinessDaysSincePreviousEvent
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.BusinessDaysUntilNextEvent
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.BusinessDaysUntilNextEvent
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.ExponentialWeightedMovingAverage
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.ExponentialWeightedMovingAverage
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.ExponentialWeightedMovingStdDev
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.ExponentialWeightedMovingStdDev
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.Latest
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.Latest
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.MaxDrawdown
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.MaxDrawdown
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.Returns
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.Returns
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.RollingLinearRegressionOfReturns
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.RollingLinearRegressionOfReturns
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.RollingPearsonOfReturns
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.RollingPearsonOfReturns
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.RollingSpearmanOfReturns
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.RollingSpearmanOfReturns
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.RSI
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.RSI
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.SimpleMovingAverage
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.SimpleMovingAverage
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.VWAP
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.VWAP
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.pipeline.factors.WeightedAverageValue
|
||||
:members:
|
||||
.. .. autoclass:: zipline.pipeline.factors.WeightedAverageValue
|
||||
.. :members:
|
||||
|
||||
Pipeline Engine
|
||||
```````````````
|
||||
.. Pipeline Engine
|
||||
.. ```````````````
|
||||
|
||||
.. autoclass:: zipline.pipeline.engine.PipelineEngine
|
||||
:members: run_pipeline, run_chunked_pipeline
|
||||
:member-order: bysource
|
||||
.. .. autoclass:: zipline.pipeline.engine.PipelineEngine
|
||||
.. :members: run_pipeline, run_chunked_pipeline
|
||||
.. :member-order: bysource
|
||||
|
||||
.. autoclass:: zipline.pipeline.engine.SimplePipelineEngine
|
||||
:members: __init__, run_pipeline, run_chunked_pipeline
|
||||
:member-order: bysource
|
||||
.. .. autoclass:: zipline.pipeline.engine.SimplePipelineEngine
|
||||
.. :members: __init__, run_pipeline, run_chunked_pipeline
|
||||
.. :member-order: bysource
|
||||
|
||||
.. autofunction:: zipline.pipeline.engine.default_populate_initial_workspace
|
||||
.. .. autofunction:: zipline.pipeline.engine.default_populate_initial_workspace
|
||||
|
||||
Data Loaders
|
||||
````````````
|
||||
.. Data Loaders
|
||||
.. ````````````
|
||||
|
||||
.. autoclass:: zipline.pipeline.loaders.equity_pricing_loader.USEquityPricingLoader
|
||||
:members: __init__, from_files, load_adjusted_array
|
||||
:member-order: bysource
|
||||
.. .. autoclass:: zipline.pipeline.loaders.equity_pricing_loader.USEquityPricingLoader
|
||||
.. :members: __init__, from_files, load_adjusted_array
|
||||
.. :member-order: bysource
|
||||
|
||||
Asset Metadata
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: zipline.assets.Asset
|
||||
.. autoclass:: catalyst.assets.Asset
|
||||
:members:
|
||||
|
||||
.. autoclass:: zipline.assets.Equity
|
||||
:members:
|
||||
|
||||
.. autoclass:: zipline.assets.Future
|
||||
:members:
|
||||
|
||||
.. autoclass:: zipline.assets.AssetConvertible
|
||||
.. autoclass:: catalyst.assets.AssetConvertible
|
||||
:members:
|
||||
|
||||
|
||||
Trading Calendar API
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autofunction:: zipline.utils.calendars.get_calendar
|
||||
.. autofunction:: catalyst.utils.calendars.get_calendar
|
||||
|
||||
.. autoclass:: zipline.utils.calendars.TradingCalendar
|
||||
.. autoclass:: catalyst.utils.calendars.TradingCalendar
|
||||
:members:
|
||||
|
||||
.. autofunction:: zipline.utils.calendars.register_calendar
|
||||
.. autofunction:: catalyst.utils.calendars.register_calendar
|
||||
|
||||
.. autofunction:: zipline.utils.calendars.register_calendar_type
|
||||
.. autofunction:: catalyst.utils.calendars.register_calendar_type
|
||||
|
||||
.. autofunction:: zipline.utils.calendars.deregister_calendar
|
||||
.. autofunction:: catalyst.utils.calendars.deregister_calendar
|
||||
|
||||
.. autofunction:: zipline.utils.calendars.clear_calendars
|
||||
.. autofunction:: catalyst.utils.calendars.clear_calendars
|
||||
|
||||
|
||||
Data API
|
||||
~~~~~~~~
|
||||
|
||||
Writers
|
||||
```````
|
||||
.. autoclass:: zipline.data.minute_bars.BcolzMinuteBarWriter
|
||||
:members:
|
||||
.. Writers
|
||||
.. ```````
|
||||
.. .. autoclass:: zipline.data.minute_bars.BcolzMinuteBarWriter
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.data.us_equity_pricing.BcolzDailyBarWriter
|
||||
:members:
|
||||
.. .. autoclass:: zipline.data.us_equity_pricing.BcolzDailyBarWriter
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.data.us_equity_pricing.SQLiteAdjustmentWriter
|
||||
:members:
|
||||
.. .. autoclass:: zipline.data.us_equity_pricing.SQLiteAdjustmentWriter
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.assets.AssetDBWriter
|
||||
:members:
|
||||
.. .. autoclass:: zipline.assets.AssetDBWriter
|
||||
.. :members:
|
||||
|
||||
Readers
|
||||
```````
|
||||
.. autoclass:: zipline.data.minute_bars.BcolzMinuteBarReader
|
||||
:members:
|
||||
.. Readers
|
||||
.. ```````
|
||||
.. .. autoclass:: zipline.data.minute_bars.BcolzMinuteBarReader
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.data.us_equity_pricing.BcolzDailyBarReader
|
||||
:members:
|
||||
.. .. autoclass:: zipline.data.us_equity_pricing.BcolzDailyBarReader
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.data.us_equity_pricing.SQLiteAdjustmentReader
|
||||
:members:
|
||||
.. .. autoclass:: zipline.data.us_equity_pricing.SQLiteAdjustmentReader
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.assets.AssetFinder
|
||||
:members:
|
||||
.. .. autoclass:: zipline.assets.AssetFinder
|
||||
.. :members:
|
||||
|
||||
.. autoclass:: zipline.data.data_portal.DataPortal
|
||||
:members:
|
||||
.. .. autoclass:: zipline.data.data_portal.DataPortal
|
||||
.. :members:
|
||||
|
||||
Bundles
|
||||
```````
|
||||
.. autofunction:: zipline.data.bundles.register
|
||||
.. Bundles
|
||||
.. ```````
|
||||
.. .. autofunction:: zipline.data.bundles.register
|
||||
|
||||
.. autofunction:: zipline.data.bundles.ingest(name, environ=os.environ, date=None, show_progress=True)
|
||||
.. .. autofunction:: zipline.data.bundles.ingest(name, environ=os.environ, date=None, show_progress=True)
|
||||
|
||||
.. autofunction:: zipline.data.bundles.load(name, environ=os.environ, date=None)
|
||||
.. .. autofunction:: zipline.data.bundles.load(name, environ=os.environ, date=None)
|
||||
|
||||
.. autofunction:: zipline.data.bundles.unregister
|
||||
.. .. autofunction:: zipline.data.bundles.unregister
|
||||
|
||||
.. data:: zipline.data.bundles.bundles
|
||||
.. .. data:: zipline.data.bundles.bundles
|
||||
|
||||
The bundles that have been registered as a mapping from bundle name to bundle
|
||||
data. This mapping is immutable and should only be updated through
|
||||
:func:`~zipline.data.bundles.register` or
|
||||
:func:`~zipline.data.bundles.unregister`.
|
||||
.. The bundles that have been registered as a mapping from bundle name to bundle
|
||||
.. data. This mapping is immutable and should only be updated through
|
||||
.. :func:`~zipline.data.bundles.register` or
|
||||
.. :func:`~zipline.data.bundles.unregister`.
|
||||
|
||||
.. autofunction:: zipline.data.bundles.yahoo_equities
|
||||
.. .. autofunction:: zipline.data.bundles.yahoo_equities
|
||||
|
||||
|
||||
|
||||
@@ -362,16 +356,16 @@ Utilities
|
||||
Caching
|
||||
```````
|
||||
|
||||
.. autoclass:: zipline.utils.cache.CachedObject
|
||||
.. autoclass:: catalyst.utils.cache.CachedObject
|
||||
|
||||
.. autoclass:: zipline.utils.cache.ExpiringCache
|
||||
.. autoclass:: catalyst.utils.cache.ExpiringCache
|
||||
|
||||
.. autoclass:: zipline.utils.cache.dataframe_cache
|
||||
.. autoclass:: catalyst.utils.cache.dataframe_cache
|
||||
|
||||
.. autoclass:: zipline.utils.cache.working_file
|
||||
.. autoclass:: catalyst.utils.cache.working_file
|
||||
|
||||
.. autoclass:: zipline.utils.cache.working_dir
|
||||
.. autoclass:: catalyst.utils.cache.working_dir
|
||||
|
||||
Command Line
|
||||
````````````
|
||||
.. autofunction:: zipline.utils.cli.maybe_show_progress
|
||||
.. autofunction:: catalyst.utils.cli.maybe_show_progress
|
||||
|
||||
@@ -168,7 +168,7 @@ We'll start with the CLI, and introduce the ``run_algorithm()`` in the last
|
||||
example of this tutorial. Some of the :doc:`example algorithms <example-algos>`
|
||||
provide instructions on how to run them both from the CLI, and using the
|
||||
:func:`~catalyst.run_algorithm` function. For the third method, refer to the
|
||||
corresponding section on :doc:`Catalyst & Jupyter Notebook <jupyter>` after you
|
||||
corresponding section on :ref:`Catalyst & Jupyter Notebook <jupyter>` after you
|
||||
have assimilated the contents of this tutorial.
|
||||
|
||||
Command line interface
|
||||
@@ -473,6 +473,7 @@ Which we execute by running:
|
||||
</div>
|
||||
|
||||
|
|
||||
|
||||
There is a row for each trading day, starting on the first day of our
|
||||
simulation Jan 1st, 2016. In the columns you can find various
|
||||
information about the state of your algorithm. The column
|
||||
@@ -518,7 +519,7 @@ alongside enigma-catalyst (with the exception of the ``Conda`` install, where it
|
||||
was included by default inside the conda environment we created). If for any
|
||||
reason you don't have it installed, you can add it by running:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: bash
|
||||
|
||||
(catalyst)$ pip install matplotlib
|
||||
|
||||
@@ -806,6 +807,7 @@ the ``scikit-learn`` functions require ``numpy.ndarray``\ s rather than
|
||||
``pandas.DataFrame``\ s, so you can simply pass the underlying
|
||||
``ndarray`` of a ``DataFrame`` via ``.values``).
|
||||
|
||||
.. _jupyter:
|
||||
|
||||
Jupyter Notebook
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -826,13 +828,13 @@ In order to use Jupyter Notebook, you first have to install it inside your
|
||||
environment. It's available as ``pip`` package, so regardless of how you
|
||||
installed Catalyst, go inside your catalyst environemnt and run:
|
||||
|
||||
.. code:: bash
|
||||
.. code-block:: bash
|
||||
|
||||
(catalyst)$ pip install jupyter
|
||||
|
||||
Once you have Jupyter Notebook installed, every time you want to use it run:
|
||||
|
||||
.. code:: bash
|
||||
.. code-block:: bash
|
||||
|
||||
(catalyst)$ jupyter notebook
|
||||
|
||||
@@ -846,7 +848,7 @@ Before running your algorithms inside the Jupyter Notebook, remember to ingest
|
||||
the data from the command line interface (CLI). In the example below, you would
|
||||
need to run first:
|
||||
|
||||
.. code:: bash
|
||||
.. code-block:: bash
|
||||
|
||||
catalyst ingest-exchange -x bitfinex -i btc_usd
|
||||
|
||||
|
||||
+5
-2
@@ -27,8 +27,8 @@ extlinks = {
|
||||
|
||||
# -- Docstrings ---------------------------------------------------------------
|
||||
|
||||
#extensions += ['numpydoc']
|
||||
#numpydoc_show_class_members = False
|
||||
extensions += ['numpydoc']
|
||||
numpydoc_show_class_members = False
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['.templates']
|
||||
@@ -97,3 +97,6 @@ intersphinx_mapping = {
|
||||
doctest_global_setup = "import catalyst"
|
||||
|
||||
todo_include_todos = True
|
||||
|
||||
suppress_warnings = ['image.nonlocal_uri']
|
||||
|
||||
|
||||
@@ -36,25 +36,15 @@ Finally, you can build the C extensions by running:
|
||||
|
||||
$ python setup.py build_ext --inplace
|
||||
|
||||
.. To finish, make sure `tests`__ pass.
|
||||
Development with Docker
|
||||
-----------------------
|
||||
|
||||
.. __ #style-guide-running-tests
|
||||
If you want to work with zipline using a `Docker`__ container, you'll need to
|
||||
build the ``Dockerfile`` in the Zipline root directory, and then build
|
||||
``Dockerfile-dev``. Instructions for building both containers can be found in
|
||||
``Dockerfile`` and ``Dockerfile-dev``, respectively.
|
||||
|
||||
.. If you get an error running nosetests after setting up a fresh virtualenv, please try running
|
||||
|
||||
.. code-block
|
||||
|
||||
.. # where zipline is the name of your virtualenv
|
||||
.. $ deactivate zipline
|
||||
.. $ workon zipline
|
||||
|
||||
|
||||
.. Development with Docker
|
||||
.. -----------------------
|
||||
|
||||
..If you want to work with zipline using a `Docker`__ container, you'll need to build the ``Dockerfile`` in the Zipline root directory, and then build ``Dockerfile-dev``. Instructions for building both containers can be found in ``Dockerfile`` and ``Dockerfile-dev``, respectively.
|
||||
|
||||
.. __ https://docs.docker.com/get-started/
|
||||
__ https://docs.docker.com/get-started/
|
||||
|
||||
Git Branching Structure
|
||||
-----------------------
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
|
||||
|
||||
Example Algorithms
|
||||
==================
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
.. include:: ../../README.rst
|
||||
|
||||
|
|
||||
|
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -298,7 +298,7 @@ Troubleshooting ``pip`` Install
|
||||
.. _pipenv:
|
||||
|
||||
Installing with ``pipenv``
|
||||
-------------------------
|
||||
--------------------------
|
||||
|
||||
Installing Catalyst via ``pipenv`` is perhaps easier that installing it via
|
||||
``pip`` itself but you need to install ``pipenv`` first via ``pip``.
|
||||
@@ -476,6 +476,7 @@ mentioned above are as follows:
|
||||
default you get 0 as the Value Data)
|
||||
|
||||
|
|
||||
|
||||
- **The installer has encountered an unexpected error installing this package.
|
||||
This may indicate a problem with this package. The error code is 2503.**
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ Currency symbols (e.g. btc, eth, ltc) follow the Bittrex convention.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
.. code-block:: json
|
||||
.. code:: python
|
||||
|
||||
# With Bitfinex
|
||||
bitcoin_usd_asset = symbol('btc_usd')
|
||||
|
||||
@@ -2,7 +2,23 @@
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
Version 0.5.0
|
||||
Version 0.5.3
|
||||
^^^^^^^^^^^^^
|
||||
**Release Date**: 2018-02-09
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
- Fixed an issue with last candle in backtesting :issue:`219`
|
||||
|
||||
Version 0.5.2
|
||||
^^^^^^^^^^^^^
|
||||
**Release Date**: 2018-02-08
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
- Fixed an issue with live candle values :issue:`216` and :issue:`199`
|
||||
|
||||
Version 0.5.1
|
||||
^^^^^^^^^^^^^
|
||||
**Release Date**: 2018-02-07
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ Installation: MacOS
|
||||
|
||||
|
|
||||
|
|
||||
|
||||
Installation: Windows
|
||||
---------------------
|
||||
|
||||
@@ -21,6 +22,7 @@ Where things go smoothly:
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/H8HqcEbZmkk" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
|
|
||||
|
||||
Where things don't:
|
||||
|
||||
.. raw:: html
|
||||
@@ -29,6 +31,7 @@ Where things don't:
|
||||
|
||||
|
|
||||
|
|
||||
|
||||
Backtesting a Strategy
|
||||
----------------------
|
||||
|
||||
@@ -44,6 +47,7 @@ sell. Hopefully, we’ll ride the waves.
|
||||
|
||||
|
|
||||
|
|
||||
|
||||
Live Trading a Strategy
|
||||
-----------------------
|
||||
|
||||
@@ -54,5 +58,6 @@ 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>
|
||||
|
||||
|
|
||||
|
|
||||
|
|
||||
@@ -16,7 +16,7 @@ babel==1.3
|
||||
docutils==0.12
|
||||
snowballstemmer==1.2.0
|
||||
sphinx-rtd-theme==0.1.8
|
||||
sphinx==1.3.4
|
||||
sphinx==1.6.7
|
||||
pbr==1.10.0
|
||||
|
||||
mock==2.0.0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Sphinx>=1.3.2
|
||||
Sphinx==1.6.7
|
||||
numpydoc>=0.5.0
|
||||
sphinx-autobuild==0.6.0
|
||||
docutils==0.12
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import pandas as pd
|
||||
from logbook import Logger
|
||||
|
||||
from catalyst.testing import ZiplineTestCase
|
||||
from catalyst.testing.fixtures import WithLogger
|
||||
from catalyst.exchange.utils.stats_utils import set_print_settings
|
||||
from .base import BaseExchangeTestCase
|
||||
from catalyst.exchange.ccxt.ccxt_exchange import CCXT
|
||||
from catalyst.exchange.exchange_execution import ExchangeLimitOrder
|
||||
@@ -15,7 +14,7 @@ log = Logger('test_ccxt')
|
||||
class TestCCXT(BaseExchangeTestCase):
|
||||
@classmethod
|
||||
def setup(self):
|
||||
exchange_name = 'binance'
|
||||
exchange_name = 'bittrex'
|
||||
auth = get_exchange_auth(exchange_name)
|
||||
self.exchange = CCXT(
|
||||
exchange_name=exchange_name,
|
||||
@@ -58,15 +57,20 @@ class TestCCXT(BaseExchangeTestCase):
|
||||
def test_get_candles(self):
|
||||
log.info('retrieving candles')
|
||||
candles = self.exchange.get_candles(
|
||||
freq='30T',
|
||||
freq='1T',
|
||||
assets=[self.exchange.get_asset('eth_btc')],
|
||||
bar_count=200,
|
||||
start_dt=pd.to_datetime('2017-09-01', utc=True)
|
||||
# start_dt=pd.to_datetime('2017-09-01', utc=True),
|
||||
)
|
||||
|
||||
for asset in candles:
|
||||
df = pd.DataFrame(candles[asset])
|
||||
df.set_index('last_traded', drop=True, inplace=True)
|
||||
|
||||
set_print_settings()
|
||||
print('got {} candles'.format(len(df)))
|
||||
print(df.head(10))
|
||||
print(df.tail(10))
|
||||
pass
|
||||
|
||||
def test_tickers(self):
|
||||
|
||||
@@ -2,6 +2,7 @@ import random
|
||||
|
||||
import os
|
||||
import pandas as pd
|
||||
from datetime import timedelta
|
||||
from logbook import TestHandler
|
||||
from pandas.util.testing import assert_frame_equal
|
||||
|
||||
@@ -12,6 +13,7 @@ from catalyst.exchange.utils.exchange_utils import get_candles_df
|
||||
from catalyst.exchange.utils.factory import get_exchange
|
||||
from catalyst.exchange.utils.test_utils import output_df, \
|
||||
select_random_assets
|
||||
from catalyst.exchange.utils.stats_utils import set_print_settings
|
||||
|
||||
pd.set_option('display.expand_frame_repr', False)
|
||||
pd.set_option('precision', 8)
|
||||
@@ -58,6 +60,12 @@ class TestSuiteBundle:
|
||||
|
||||
log_catcher = TestHandler()
|
||||
with log_catcher:
|
||||
symbols = [asset.symbol for asset in assets]
|
||||
print(
|
||||
'comparing data for {}/{} with {} timeframe until {}'.format(
|
||||
exchange.name, symbols, freq, end_dt
|
||||
)
|
||||
)
|
||||
data['bundle'] = data_portal.get_history_window(
|
||||
assets=assets,
|
||||
end_dt=end_dt,
|
||||
@@ -66,6 +74,12 @@ class TestSuiteBundle:
|
||||
field='close',
|
||||
data_frequency=data_frequency,
|
||||
)
|
||||
set_print_settings()
|
||||
print(
|
||||
'the bundle first / last row:\n{}'.format(
|
||||
data['bundle'].iloc[[-1, 0]]
|
||||
)
|
||||
)
|
||||
candles = exchange.get_candles(
|
||||
end_dt=end_dt,
|
||||
freq=freq,
|
||||
@@ -79,6 +93,11 @@ class TestSuiteBundle:
|
||||
bar_count=bar_count,
|
||||
end_dt=end_dt,
|
||||
)
|
||||
print(
|
||||
'the exchange first / last row:\n{}'.format(
|
||||
data['exchange'].iloc[[-1, 0]]
|
||||
)
|
||||
)
|
||||
for source in data:
|
||||
df = data[source]
|
||||
path, folder = output_df(
|
||||
@@ -106,6 +125,65 @@ class TestSuiteBundle:
|
||||
|
||||
pass
|
||||
|
||||
def compare_current_with_last_candle(self, exchange, assets, end_dt,
|
||||
freq, data_frequency, data_portal):
|
||||
"""
|
||||
Creates DataFrames from the bundle and exchange for the specified
|
||||
data set.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
exchange: Exchange
|
||||
assets
|
||||
end_dt
|
||||
bar_count
|
||||
freq
|
||||
data_frequency
|
||||
data_portal
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
"""
|
||||
data = dict()
|
||||
|
||||
assets = sorted(assets, key=lambda a: a.symbol)
|
||||
log_catcher = TestHandler()
|
||||
with log_catcher:
|
||||
symbols = [asset.symbol for asset in assets]
|
||||
print(
|
||||
'comparing data for {}/{} with {} timeframe on {}'.format(
|
||||
exchange.name, symbols, freq, end_dt
|
||||
)
|
||||
)
|
||||
data['candle'] = data_portal.get_history_window(
|
||||
assets=assets,
|
||||
end_dt=end_dt,
|
||||
bar_count=1,
|
||||
frequency=freq,
|
||||
field='close',
|
||||
data_frequency=data_frequency,
|
||||
)
|
||||
set_print_settings()
|
||||
print(
|
||||
'the bundle first / last row:\n{}'.format(
|
||||
data['candle'].iloc[[-1]]
|
||||
)
|
||||
)
|
||||
current = data_portal.get_spot_value(
|
||||
assets=assets,
|
||||
field='close',
|
||||
dt=end_dt,
|
||||
data_frequency=data_frequency,
|
||||
)
|
||||
data['current'] = pd.Series(data=current, index=assets)
|
||||
print(
|
||||
'the current price:\n{}'.format(
|
||||
data['current']
|
||||
)
|
||||
)
|
||||
pass
|
||||
|
||||
def test_validate_bundles(self):
|
||||
# exchange_population = 3
|
||||
asset_population = 3
|
||||
@@ -139,6 +217,7 @@ class TestSuiteBundle:
|
||||
if end_dt is None or asset_end_dt < end_dt:
|
||||
end_dt = asset_end_dt
|
||||
|
||||
end_dt = end_dt + timedelta(minutes=3)
|
||||
dt_range = pd.date_range(
|
||||
end=end_dt, periods=bar_count, freq=freq
|
||||
)
|
||||
@@ -152,3 +231,45 @@ class TestSuiteBundle:
|
||||
data_portal=data_portal,
|
||||
)
|
||||
pass
|
||||
|
||||
def test_validate_last_candle(self):
|
||||
# exchange_population = 3
|
||||
asset_population = 3
|
||||
data_frequency = random.choice(['minute'])
|
||||
|
||||
# bundle = 'dailyBundle' if data_frequency
|
||||
# == 'daily' else 'minuteBundle'
|
||||
# exchanges = select_random_exchanges(
|
||||
# population=exchange_population,
|
||||
# features=[bundle],
|
||||
# ) # Type: list[Exchange]
|
||||
exchanges = [get_exchange('poloniex', skip_init=True)]
|
||||
|
||||
data_portal = TestSuiteBundle.get_data_portal(exchanges)
|
||||
for exchange in exchanges:
|
||||
exchange.init()
|
||||
|
||||
frequencies = exchange.get_candle_frequencies(data_frequency)
|
||||
freq = random.sample(frequencies, 1)[0]
|
||||
|
||||
assets = select_random_assets(
|
||||
exchange.assets, asset_population
|
||||
)
|
||||
end_dt = None
|
||||
for asset in assets:
|
||||
attribute = 'end_{}'.format(data_frequency)
|
||||
asset_end_dt = getattr(asset, attribute)
|
||||
|
||||
if end_dt is None or asset_end_dt < end_dt:
|
||||
end_dt = asset_end_dt
|
||||
|
||||
end_dt = end_dt + timedelta(minutes=3)
|
||||
self.compare_current_with_last_candle(
|
||||
exchange=exchange,
|
||||
assets=assets,
|
||||
end_dt=end_dt,
|
||||
freq=freq,
|
||||
data_frequency=data_frequency,
|
||||
data_portal=data_portal,
|
||||
)
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user