stable/freqtrade/analyze.py

137 lines
4.5 KiB
Python
Raw Normal View History

2017-11-18 07:34:32 +00:00
"""
Functions to analyze ticker data with indicators and produce buy and sell signals
"""
2017-11-14 17:06:03 +00:00
from enum import Enum
2017-10-06 10:22:04 +00:00
import logging
2017-05-24 19:52:41 +00:00
from datetime import timedelta
2017-10-06 10:22:04 +00:00
2017-08-27 14:12:28 +00:00
import arrow
import talib.abstract as ta
from pandas import DataFrame, to_datetime
2017-11-09 21:29:23 +00:00
from freqtrade.exchange import get_ticker_history
2017-11-18 07:34:57 +00:00
from freqtrade.vendor.qtpylib.indicators import awesome_oscillator, crossed_above
2017-05-24 19:52:41 +00:00
logger = logging.getLogger(__name__)
2017-11-14 17:06:03 +00:00
class SignalType(Enum):
2017-11-18 07:34:32 +00:00
""" Enum to distinguish between buy and sell signals """
2017-11-14 17:06:03 +00:00
BUY = "buy"
SELL = "sell"
2017-05-24 19:52:41 +00:00
def parse_ticker_dataframe(ticker: list) -> DataFrame:
"""
Analyses the trend for the given ticker history
:param ticker: See exchange.get_ticker_history
:return: DataFrame
"""
2017-11-07 19:13:36 +00:00
columns = {'C': 'close', 'V': 'volume', 'O': 'open', 'H': 'high', 'L': 'low', 'T': 'date'}
frame = DataFrame(ticker) \
.drop('BV', 1) \
2017-11-07 19:13:36 +00:00
.rename(columns=columns)
frame['date'] = to_datetime(frame['date'], utc=True, infer_datetime_format=True)
frame.sort_values('date', inplace=True)
return frame
2017-10-06 10:22:04 +00:00
def populate_indicators(dataframe: DataFrame) -> DataFrame:
"""
Adds several different TA indicators to the given DataFrame
"""
dataframe['sar'] = ta.SAR(dataframe)
2017-09-12 08:47:23 +00:00
dataframe['adx'] = ta.ADX(dataframe)
2017-09-29 06:37:45 +00:00
stoch = ta.STOCHF(dataframe)
dataframe['fastd'] = stoch['fastd']
dataframe['fastk'] = stoch['fastk']
dataframe['blower'] = ta.BBANDS(dataframe, nbdevup=2, nbdevdn=2)['lowerband']
dataframe['sma'] = ta.SMA(dataframe, timeperiod=40)
dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)
2017-09-29 06:37:45 +00:00
dataframe['mfi'] = ta.MFI(dataframe)
dataframe['rsi'] = ta.RSI(dataframe)
dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
dataframe['ao'] = awesome_oscillator(dataframe)
2017-10-28 13:43:34 +00:00
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
2017-11-12 07:13:54 +00:00
hilbert = ta.HT_SINE(dataframe)
dataframe['htsine'] = hilbert['sine']
dataframe['htleadsine'] = hilbert['leadsine']
2017-05-24 19:52:41 +00:00
return dataframe
def populate_buy_trend(dataframe: DataFrame) -> DataFrame:
2017-05-24 19:52:41 +00:00
"""
2017-11-14 18:28:31 +00:00
Based on TA indicators, populates the buy signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[
2017-09-29 06:37:45 +00:00
(dataframe['close'] < dataframe['sma']) &
(dataframe['tema'] <= dataframe['blower']) &
(dataframe['mfi'] < 25) &
(dataframe['fastd'] < 25) &
(dataframe['adx'] > 30),
2017-09-12 08:47:23 +00:00
'buy'] = 1
2017-05-24 19:52:41 +00:00
return dataframe
2017-11-14 18:28:31 +00:00
def populate_sell_trend(dataframe: DataFrame) -> DataFrame:
"""
Based on TA indicators, populates the sell signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[
2017-11-14 18:28:31 +00:00
(crossed_above(dataframe['rsi'], 70)),
'sell'] = 1
return dataframe
2017-05-24 19:52:41 +00:00
def analyze_ticker(pair: str) -> DataFrame:
"""
Get ticker data for given currency pair, push it to a DataFrame and
add several TA indicators and buy signal to it
:return DataFrame with ticker data and indicator data
"""
ticker_hist = get_ticker_history(pair)
if not ticker_hist:
logger.warning('Empty ticker history for pair %s', pair)
return DataFrame()
2017-10-06 10:22:04 +00:00
dataframe = parse_ticker_dataframe(ticker_hist)
dataframe = populate_indicators(dataframe)
dataframe = populate_buy_trend(dataframe)
2017-11-14 18:28:31 +00:00
dataframe = populate_sell_trend(dataframe)
# TODO: buy_price and sell_price are only used by the plotter, should probably be moved there
dataframe.loc[dataframe['buy'] == 1, 'buy_price'] = dataframe['close']
dataframe.loc[dataframe['sell'] == 1, 'sell_price'] = dataframe['close']
return dataframe
2017-10-06 10:22:04 +00:00
2017-11-14 17:06:03 +00:00
def get_signal(pair: str, signal: SignalType) -> bool:
2017-05-24 19:52:41 +00:00
"""
2017-11-14 17:06:03 +00:00
Calculates current signal based several technical analysis indicators
2017-05-24 19:52:41 +00:00
:param pair: pair in format BTC_ANT or BTC-ANT
:return: True if pair is good for buying, False otherwise
2017-05-24 19:52:41 +00:00
"""
dataframe = analyze_ticker(pair)
2017-09-27 22:43:32 +00:00
if dataframe.empty:
return False
2017-05-24 19:52:41 +00:00
latest = dataframe.iloc[-1]
# Check if dataframe is out of date
signal_date = arrow.get(latest['date'])
if signal_date < arrow.now() - timedelta(minutes=10):
return False
2017-11-14 17:06:03 +00:00
result = latest[signal.value] == 1
logger.debug('%s_trigger: %s (pair=%s, signal=%s)', signal.value, latest['date'], pair, result)
return result