mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-06 05:14:38 +08:00
Polishing the algorithm
This commit is contained in:
@@ -8,8 +8,7 @@ from catalyst.api import (
|
||||
get_open_orders,
|
||||
)
|
||||
from catalyst.errors import ZiplineError
|
||||
import matplotlib.pyplot as plt
|
||||
import pyfolio as pf
|
||||
import talib
|
||||
|
||||
algo_namespace = 'buy_the_dip_live'
|
||||
log = Logger(algo_namespace)
|
||||
@@ -17,12 +16,12 @@ log = Logger(algo_namespace)
|
||||
|
||||
def initialize(context):
|
||||
log.info('initializing algo')
|
||||
context.ASSET_NAME = 'EOS_USD'
|
||||
context.TICK_SIZE = 1000.0
|
||||
context.ASSET_NAME = 'IOT_USD'
|
||||
context.asset = symbol(context.ASSET_NAME)
|
||||
|
||||
context.TARGET_POSITIONS = 100
|
||||
context.BUY_INCREMENT = 1
|
||||
context.TARGET_POSITIONS = 200
|
||||
context.PROFIT_TARGET = 0.1
|
||||
context.SLIPPAGE_ALLOWED = 0.02
|
||||
|
||||
context.retry_check_open_orders = 2
|
||||
context.retry_update_portfolio = 2
|
||||
@@ -32,28 +31,22 @@ def initialize(context):
|
||||
|
||||
|
||||
def _handle_data(context, data):
|
||||
# price_history = data.history(symbol('iot_usd'),
|
||||
# fields='price',
|
||||
# bar_count=20,
|
||||
# frequency='1d'
|
||||
# )
|
||||
# ohlc = data.history([context.asset, symbol('iot_usd')],
|
||||
# fields='price',
|
||||
# bar_count=20,
|
||||
# frequency='1d'
|
||||
# )
|
||||
ohlc = data.history(context.asset,
|
||||
fields=['price', 'volume'],
|
||||
bar_count=120,
|
||||
frequency='1m'
|
||||
)
|
||||
# ohlc = data.history([context.asset, symbol('iot_usd')],
|
||||
# fields=['price', 'volume'],
|
||||
# bar_count=20,
|
||||
# frequency='1d'
|
||||
# )
|
||||
prices = data.history(
|
||||
context.asset,
|
||||
fields='price',
|
||||
bar_count=20,
|
||||
frequency='15m'
|
||||
)
|
||||
rsi = talib.RSI(prices.values, timeperiod=14)[-1]
|
||||
log.info('got rsi: {}'.format(rsi))
|
||||
|
||||
hist_price = ohlc['price']
|
||||
# Buying more when RSI is low, this should lower our cost basis
|
||||
if rsi <= 40:
|
||||
buy_increment = 2
|
||||
elif rsi <= 30:
|
||||
buy_increment = 5
|
||||
else:
|
||||
buy_increment = 1
|
||||
|
||||
cash = context.portfolio.cash
|
||||
log.info('base currency available: {cash}'.format(cash=cash))
|
||||
@@ -66,7 +59,7 @@ def _handle_data(context, data):
|
||||
log.info('skipping bar until all open orders execute')
|
||||
return
|
||||
|
||||
if price * context.BUY_INCREMENT > cash:
|
||||
if price * buy_increment > cash:
|
||||
log.info('not enough base currency to consider buying')
|
||||
return
|
||||
|
||||
@@ -83,12 +76,13 @@ def _handle_data(context, data):
|
||||
)
|
||||
if price < cost_basis:
|
||||
is_buy = True
|
||||
elif price > cost_basis * 1.1:
|
||||
log.info('price higher than cost basis, taking profit')
|
||||
elif price > cost_basis * (1 + context.PROFIT_TARGET) or rsi > 70:
|
||||
profit = (price * position.amount) - (cost_basis * position.amount)
|
||||
log.info('closing position, taking profit: {}'.format(profit))
|
||||
order_target_percent(
|
||||
asset=context.asset,
|
||||
target=0,
|
||||
limit_price=price * 0.95,
|
||||
limit_price=price * (1 - context.SLIPPAGE_ALLOWED),
|
||||
)
|
||||
else:
|
||||
log.info('no buy or sell opportunity found')
|
||||
@@ -104,8 +98,8 @@ def _handle_data(context, data):
|
||||
)
|
||||
order(
|
||||
asset=context.asset,
|
||||
amount=context.BUY_INCREMENT,
|
||||
limit_price=price * 1.1
|
||||
amount=buy_increment,
|
||||
limit_price=price * (1 + context.SLIPPAGE_ALLOWED)
|
||||
)
|
||||
|
||||
record(
|
||||
@@ -134,17 +128,7 @@ def handle_data(context, data):
|
||||
|
||||
|
||||
def analyze(context, stats):
|
||||
# pnl, = plt.plot(stats.index, stats['pnl'], '-',
|
||||
# color='blue',
|
||||
# linewidth=1.0,
|
||||
# label='P&L',
|
||||
# )
|
||||
#
|
||||
# plt.legend(handles=[pnl])
|
||||
# plt.show()
|
||||
returns, positions, transactions, gross_lev = \
|
||||
pf.utils.extract_rets_pos_txn_from_zipline(stats)
|
||||
|
||||
log.info('the full stats:\n{}'.format(stats))
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -226,8 +226,12 @@ class ExchangeTradingAlgorithm(TradingAlgorithm):
|
||||
shorts_count=pos_stats.shorts_count,
|
||||
)
|
||||
|
||||
# Merging cumulative risk
|
||||
stats.update(tracker.cumulative_risk_metrics.to_dict())
|
||||
|
||||
# Merging latest recorded variables
|
||||
stats.update(self.recorded_vars)
|
||||
|
||||
stats['positions'] = period.position_tracker.get_positions_list()
|
||||
|
||||
# we want the key to be absent, not just empty
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
import pytz
|
||||
import six
|
||||
import base64
|
||||
@@ -279,17 +280,43 @@ class Bitfinex(Exchange):
|
||||
|
||||
def get_candles(self, data_frequency, assets,
|
||||
end_dt=None, bar_count=None, limit=None):
|
||||
"""
|
||||
Retrieve OHLVC candles from Bitfinex
|
||||
|
||||
# TODO: support all available frequencies
|
||||
start_dt = None
|
||||
if data_frequency == 'minute' or data_frequency == '1m':
|
||||
:param data_frequency:
|
||||
:param assets:
|
||||
:param end_dt:
|
||||
:param bar_count:
|
||||
:param limit:
|
||||
:return:
|
||||
|
||||
Available Frequencies
|
||||
---------------------
|
||||
'1m', '5m', '15m', '30m', '1h', '3h', '6h', '12h', '1D', '7D', '14D',
|
||||
'1M'
|
||||
"""
|
||||
freq_match = re.match(r'([0-9].*)(m|h|d)', data_frequency, re.M | re.I)
|
||||
if freq_match:
|
||||
number = int(freq_match.group(1))
|
||||
unit = freq_match.group(2)
|
||||
|
||||
if unit == 'd':
|
||||
converted_unit = 'D'
|
||||
else:
|
||||
converted_unit = unit
|
||||
|
||||
frequency = '{}{}'.format(number, converted_unit)
|
||||
allowed_frequencies = ['1m', '5m', '15m', '30m', '1h', '3h', '6h',
|
||||
'12h', '1D', '7D', '14D', '1M']
|
||||
|
||||
if frequency not in allowed_frequencies:
|
||||
raise InvalidHistoryFrequencyError(
|
||||
frequency=data_frequency
|
||||
)
|
||||
elif data_frequency == 'minute':
|
||||
frequency = '1m'
|
||||
if bar_count and end_dt:
|
||||
start_dt = end_dt - timedelta(minutes=bar_count)
|
||||
elif data_frequency == 'daily' or data_frequency == '1d':
|
||||
elif data_frequency == 'daily':
|
||||
frequency = '1D'
|
||||
if bar_count and end_dt:
|
||||
start_dt = end_dt - timedelta(days=bar_count)
|
||||
else:
|
||||
raise InvalidHistoryFrequencyError(
|
||||
frequency=data_frequency
|
||||
@@ -306,28 +333,26 @@ class Bitfinex(Exchange):
|
||||
symbol=symbol
|
||||
)
|
||||
|
||||
if start_dt and end_dt:
|
||||
if bar_count:
|
||||
is_list = True
|
||||
url += '/hist?start={start}&end={end}'.format(
|
||||
start=time.mktime(start_dt.timetuple()) * 1000,
|
||||
end=time.mktime(end_dt.timetuple()) * 1000,
|
||||
)
|
||||
url += '/hist?limit={}'.format(int(bar_count))
|
||||
else:
|
||||
is_list = False
|
||||
url += '/last'
|
||||
|
||||
try:
|
||||
response = requests.get(url)
|
||||
candles = response.json()
|
||||
except Exception as e:
|
||||
raise ExchangeRequestError(error=e)
|
||||
|
||||
if 'message' in candles:
|
||||
if 'error' in response.content:
|
||||
raise ExchangeRequestError(
|
||||
error='Unable to retrieve candles: {}'.format(
|
||||
candles['message'])
|
||||
response.content)
|
||||
)
|
||||
|
||||
candles = response.json()
|
||||
|
||||
def ohlc_from_candle(candle):
|
||||
return dict(
|
||||
open=candle[1],
|
||||
@@ -342,7 +367,8 @@ class Bitfinex(Exchange):
|
||||
|
||||
if is_list:
|
||||
ohlc_bars = []
|
||||
for candle in candles:
|
||||
# We can to list candles from old to new
|
||||
for candle in reversed(candles):
|
||||
ohlc = ohlc_from_candle(candle)
|
||||
ohlc_bars.append(ohlc)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user