mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-24 13:00:57 +08:00
BLD: Merge remote-tracking branch 'remotes/origin/data-marketplace' into develop
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
# For this example, we're going to write a simple momentum script. When the
|
||||
# stock goes up quickly, we're going to buy; when it goes down quickly, we're
|
||||
# going to sell. Hopefully we'll ride the waves.
|
||||
import os
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
import pandas as pd
|
||||
import talib
|
||||
from logbook import Logger
|
||||
|
||||
from catalyst import run_algorithm
|
||||
from catalyst.api import symbol, record, order_target_percent, get_data_source
|
||||
from catalyst.exchange.utils.stats_utils import set_print_settings, \
|
||||
get_pretty_stats
|
||||
# We give a name to the algorithm which Catalyst will use to persist its state.
|
||||
# In this example, Catalyst will create the `.catalyst/data/live_algos`
|
||||
# directory. If we stop and start the algorithm, Catalyst will resume its
|
||||
# state using the files included in the folder.
|
||||
from catalyst.utils.paths import ensure_directory
|
||||
|
||||
NAMESPACE = 'mean_reversion_simple'
|
||||
log = Logger(NAMESPACE)
|
||||
|
||||
|
||||
# To run an algorithm in Catalyst, you need two functions: initialize and
|
||||
# handle_data.
|
||||
|
||||
def initialize(context):
|
||||
# This initialize function sets any data or variables that you'll use in
|
||||
# your algorithm. For instance, you'll want to define the trading pair (or
|
||||
# trading pairs) you want to backtest. You'll also want to define any
|
||||
# parameters or values you're going to use.
|
||||
|
||||
# In our example, we're looking at Neo in Ether.
|
||||
df = get_data_source(
|
||||
'marketcap', start=context.datetime
|
||||
) # type: pd.DataFrame
|
||||
|
||||
# Keep only the top coins by market cap
|
||||
df = df.loc[df['market_cap_usd'].isin(df['market_cap_usd'].nlargest(100))]
|
||||
|
||||
set_print_settings()
|
||||
|
||||
df.sort_values(by=['market_cap_usd'], ascending=True, inplace=True)
|
||||
print('the marketplace data:\n{}'.format(df))
|
||||
|
||||
# Pick the 5 assets with the lowest market cap for trading
|
||||
quote_currency = 'eth'
|
||||
exchange = context.exchanges[next(iter(context.exchanges))]
|
||||
symbols = [a.symbol for a in exchange.assets
|
||||
if a.start_date < context.datetime]
|
||||
context.assets = []
|
||||
for currency, price in df['market_cap_usd'].iteritems():
|
||||
if len(context.assets) >= 5:
|
||||
break
|
||||
|
||||
s = '{}_{}'.format(currency.decode('utf-8'), quote_currency)
|
||||
if s in symbols:
|
||||
context.assets.append(symbol(s))
|
||||
|
||||
context.base_price = None
|
||||
context.current_day = None
|
||||
|
||||
context.RSI_OVERSOLD = 55
|
||||
context.RSI_OVERBOUGHT = 60
|
||||
context.CANDLE_SIZE = '5T'
|
||||
|
||||
context.start_time = time.time()
|
||||
|
||||
|
||||
def handle_data(context, data):
|
||||
# This handle_data function is where the real work is done. Our data is
|
||||
# minute-level tick data, and each minute is called a frame. This function
|
||||
# runs on each frame of the data.
|
||||
|
||||
# We flag the first period of each day.
|
||||
# Since cryptocurrencies trade 24/7 the `before_trading_starts` handle
|
||||
# would only execute once. This method works with minute and daily
|
||||
# frequencies.
|
||||
today = data.current_dt.floor('1D')
|
||||
if today != context.current_day:
|
||||
context.traded_today = dict()
|
||||
context.current_day = today
|
||||
|
||||
# Preparing dictionaries for asset-level data points
|
||||
volumes = dict()
|
||||
rsis = dict()
|
||||
price_values = dict()
|
||||
cash = context.portfolio.cash
|
||||
|
||||
for asset in context.assets:
|
||||
# We're computing the volume-weighted-average-price of the security
|
||||
# defined above, in the context.assets variable. For this example,
|
||||
# we're using three bars on the 15 min bars.
|
||||
|
||||
# The frequency attribute determine the bar size. We use this
|
||||
# convention for the frequency alias:
|
||||
# http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases
|
||||
prices = data.history(
|
||||
asset,
|
||||
fields='close',
|
||||
bar_count=50,
|
||||
frequency=context.CANDLE_SIZE
|
||||
)
|
||||
|
||||
# Ta-lib calculates various technical indicator based on price and
|
||||
# volume arrays.
|
||||
|
||||
# In this example, we are comp
|
||||
rsi = talib.RSI(prices.values, timeperiod=14)
|
||||
|
||||
# We need a variable for the current price of the security to compare
|
||||
# to the average. Since we are requesting two fields, data.current()
|
||||
# returns a DataFrame with
|
||||
current = data.current(asset, fields=['close', 'volume'])
|
||||
price = current['close']
|
||||
|
||||
# If base_price is not set, we use the current value. This is the
|
||||
# price at the first bar which we reference to calculate price_change.
|
||||
# if asset not in context.base_price:
|
||||
# context.base_price[asset] = price
|
||||
#
|
||||
# base_price = context.base_price[asset]
|
||||
# price_change = (price - base_price) / base_price
|
||||
|
||||
# Tracking the relevant data
|
||||
volumes[asset] = current['volume']
|
||||
rsis[asset] = rsi[-1]
|
||||
price_values[asset] = price
|
||||
# price_changes[asset] = price_change
|
||||
|
||||
# We are trying to avoid over-trading by limiting our trades to
|
||||
# one per day.
|
||||
if asset in context.traded_today:
|
||||
continue
|
||||
|
||||
# Exit if we cannot trade
|
||||
if not data.can_trade(asset):
|
||||
continue
|
||||
|
||||
# Another powerful built-in feature of the Catalyst backtester is the
|
||||
# portfolio object. The portfolio object tracks your positions, cash,
|
||||
# cost basis of specific holdings, and more. In this line, we
|
||||
# calculate how long or short our position is at this minute.
|
||||
pos_amount = context.portfolio.positions[asset].amount
|
||||
|
||||
if rsi[-1] <= context.RSI_OVERSOLD and pos_amount == 0:
|
||||
log.info(
|
||||
'{}: buying - price: {}, rsi: {}'.format(
|
||||
data.current_dt, price, rsi[-1]
|
||||
)
|
||||
)
|
||||
# Set a style for limit orders,
|
||||
limit_price = price * 1.005
|
||||
target = 1.0 / len(context.assets)
|
||||
order_target_percent(
|
||||
asset, target, limit_price=limit_price
|
||||
)
|
||||
context.traded_today[asset] = True
|
||||
|
||||
elif rsi[-1] >= context.RSI_OVERBOUGHT and pos_amount > 0:
|
||||
log.info(
|
||||
'{}: selling - price: {}, rsi: {}'.format(
|
||||
data.current_dt, price, rsi[-1]
|
||||
)
|
||||
)
|
||||
limit_price = price * 0.995
|
||||
order_target_percent(
|
||||
asset, 0, limit_price=limit_price
|
||||
)
|
||||
context.traded_today[asset] = True
|
||||
|
||||
# Now that we've collected all current data for this frame, we use
|
||||
# the record() method to save it. This data will be available as
|
||||
# a parameter of the analyze() function for further analysis.
|
||||
record(
|
||||
current_price=price_values,
|
||||
volume=volumes,
|
||||
rsi=rsis,
|
||||
cash=cash,
|
||||
)
|
||||
|
||||
|
||||
def analyze(context=None, perf=None):
|
||||
stats = get_pretty_stats(perf)
|
||||
print('the algo stats:\n{}'.format(stats))
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# The execution mode: backtest or live
|
||||
live = False
|
||||
|
||||
if live:
|
||||
run_algorithm(
|
||||
capital_base=0.1,
|
||||
initialize=initialize,
|
||||
handle_data=handle_data,
|
||||
analyze=analyze,
|
||||
exchange_name='poloniex',
|
||||
live=True,
|
||||
algo_namespace=NAMESPACE,
|
||||
base_currency='btc',
|
||||
live_graph=False,
|
||||
simulate_orders=False,
|
||||
stats_output=None,
|
||||
)
|
||||
|
||||
else:
|
||||
folder = os.path.join(
|
||||
tempfile.gettempdir(), 'catalyst', NAMESPACE
|
||||
)
|
||||
ensure_directory(folder)
|
||||
|
||||
timestr = time.strftime('%Y%m%d-%H%M%S')
|
||||
out = os.path.join(folder, '{}.p'.format(timestr))
|
||||
# catalyst run -f catalyst/examples/mean_reversion_simple.py \
|
||||
# -x bitfinex -s 2017-10-1 -e 2017-11-10 -c usdt -n mean-reversion \
|
||||
# --data-frequency minute --capital-base 10000
|
||||
run_algorithm(
|
||||
capital_base=100,
|
||||
data_frequency='minute',
|
||||
initialize=initialize,
|
||||
handle_data=handle_data,
|
||||
analyze=analyze,
|
||||
exchange_name='poloniex',
|
||||
algo_namespace=NAMESPACE,
|
||||
base_currency='eth',
|
||||
start=pd.to_datetime('2017-10-01', utc=True),
|
||||
end=pd.to_datetime('2017-10-15', utc=True),
|
||||
)
|
||||
log.info('saved perf stats: {}'.format(out))
|
||||
Reference in New Issue
Block a user