From 327f736f2065969d6971b0bdc81a2b28164121e6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Mar 2019 19:49:39 +0100 Subject: [PATCH 1/3] Add informative_pairs sample code --- user_data/strategies/Strategy001.py | 13 +++++++++++++ user_data/strategies/Strategy002.py | 13 +++++++++++++ user_data/strategies/Strategy003.py | 13 +++++++++++++ user_data/strategies/Strategy004.py | 13 +++++++++++++ user_data/strategies/Strategy005.py | 13 +++++++++++++ 5 files changed, 65 insertions(+) diff --git a/user_data/strategies/Strategy001.py b/user_data/strategies/Strategy001.py index a58fc68..2c04413 100644 --- a/user_data/strategies/Strategy001.py +++ b/user_data/strategies/Strategy001.py @@ -63,6 +63,19 @@ class Strategy001(IStrategy): 'stoploss_on_exchange': False } + def informative_pairs(self): + """ + Define additional, informative pair/interval combinations to be cached from the exchange. + These pair/interval combinations are non-tradeable, unless they are part + of the whitelist as well. + For more information, please consult the documentation + :return: List of tuples in the format (pair, interval) + Sample: return [("ETH/USDT", "5m"), + ("BTC/USDT", "15m"), + ] + """ + return [] + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame diff --git a/user_data/strategies/Strategy002.py b/user_data/strategies/Strategy002.py index 3c2ced5..5f1e7f0 100644 --- a/user_data/strategies/Strategy002.py +++ b/user_data/strategies/Strategy002.py @@ -60,6 +60,19 @@ class Strategy002(IStrategy): 'stoploss_on_exchange': False } + def informative_pairs(self): + """ + Define additional, informative pair/interval combinations to be cached from the exchange. + These pair/interval combinations are non-tradeable, unless they are part + of the whitelist as well. + For more information, please consult the documentation + :return: List of tuples in the format (pair, interval) + Sample: return [("ETH/USDT", "5m"), + ("BTC/USDT", "15m"), + ] + """ + return [] + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame diff --git a/user_data/strategies/Strategy003.py b/user_data/strategies/Strategy003.py index c369ba6..0ed7fb2 100644 --- a/user_data/strategies/Strategy003.py +++ b/user_data/strategies/Strategy003.py @@ -60,6 +60,19 @@ class Strategy003(IStrategy): 'stoploss_on_exchange': False } + def informative_pairs(self): + """ + Define additional, informative pair/interval combinations to be cached from the exchange. + These pair/interval combinations are non-tradeable, unless they are part + of the whitelist as well. + For more information, please consult the documentation + :return: List of tuples in the format (pair, interval) + Sample: return [("ETH/USDT", "5m"), + ("BTC/USDT", "15m"), + ] + """ + return [] + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame diff --git a/user_data/strategies/Strategy004.py b/user_data/strategies/Strategy004.py index ab6509e..8bb27aa 100644 --- a/user_data/strategies/Strategy004.py +++ b/user_data/strategies/Strategy004.py @@ -58,6 +58,19 @@ class Strategy004(IStrategy): 'stoploss': 'market', 'stoploss_on_exchange': False } + + def informative_pairs(self): + """ + Define additional, informative pair/interval combinations to be cached from the exchange. + These pair/interval combinations are non-tradeable, unless they are part + of the whitelist as well. + For more information, please consult the documentation + :return: List of tuples in the format (pair, interval) + Sample: return [("ETH/USDT", "5m"), + ("BTC/USDT", "15m"), + ] + """ + return [] def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ diff --git a/user_data/strategies/Strategy005.py b/user_data/strategies/Strategy005.py index b9ed18a..0f311fc 100644 --- a/user_data/strategies/Strategy005.py +++ b/user_data/strategies/Strategy005.py @@ -62,6 +62,19 @@ class Strategy005(IStrategy): 'stoploss_on_exchange': False } + def informative_pairs(self): + """ + Define additional, informative pair/interval combinations to be cached from the exchange. + These pair/interval combinations are non-tradeable, unless they are part + of the whitelist as well. + For more information, please consult the documentation + :return: List of tuples in the format (pair, interval) + Sample: return [("ETH/USDT", "5m"), + ("BTC/USDT", "15m"), + ] + """ + return [] + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame From f38805dd25c5ac84ddde3332d81b1929a8d17b0e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 09:35:30 +0100 Subject: [PATCH 2/3] Add informative pairs strategy --- user_data/strategies/InformativeSample.py | 143 ++++++++++++++++++++++ user_data/strategies/Strategy001.py | 4 - 2 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 user_data/strategies/InformativeSample.py diff --git a/user_data/strategies/InformativeSample.py b/user_data/strategies/InformativeSample.py new file mode 100644 index 0000000..93256b6 --- /dev/null +++ b/user_data/strategies/InformativeSample.py @@ -0,0 +1,143 @@ + +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +from freqtrade.data.converter import parse_ticker_dataframe +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +class InformativeSample(IStrategy): + """ + Sample strategy implementing Informative Pairs - compares ETH/BTC with USDT. + Not performing very well - but should serve as an example to use a referential pair against USD. + author@: xmatthias + github@: https://github.com/freqtrade/freqtrade-strategies + + How to use it? + > python3 freqtrade -s InformativeSample + """ + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "60": 0.01, + "30": 0.03, + "20": 0.04, + "0": 0.05 + } + + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + stoploss = -0.10 + + # Optimal ticker interval for the strategy + ticker_interval = '5m' + + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = 0.02 + + # Optimal ticker interval for the strategy + ticker_interval = '5m' + + # run "populate_indicators" only for new candle + ta_on_candle = False + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = False + + # Optional order type mapping + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + def informative_pairs(self): + """ + Define additional, informative pair/interval combinations to be cached from the exchange. + These pair/interval combinations are non-tradeable, unless they are part + of the whitelist as well. + For more information, please consult the documentation + :return: List of tuples in the format (pair, interval) + Sample: return [("ETH/USDT", "5m"), + ("BTC/USDT", "15m"), + ] + """ + + + return [(f"{self.config['stake_currency']}/USDT", self.ticker_interval)] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Adds several different TA indicators to the given DataFrame + + Performance Note: For the best performance be frugal on the number of indicators + you are using. Let uncomment only the indicator you are using in your strategies + or your hyperopt configuration, otherwise you will waste your memory and CPU usage. + """ + + dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20) + dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + if self.dp: + if self.dp.runmode == 'live': + # Compare stake-currency with USDT - using the defined ticker-interval + if (f"{self.stake_currency}/USDT", self.ticker_interval) in self.dp.available_pairs: + data = self.dp.ohlcv(pair='ETH/BTC', + ticker_interval=self.ticker_interval) + else: + # Get historic ohlcv data (cached on disk). + # data = parse_ticker_dataframe(self.dp.historic_ohlcv(pair='ETH/BTC', + # ticker_interval=self.ticker_interval), "5m") + data = self.dp.historic_ohlcv(pair=f"{self.stake_currency}/USDT", + ticker_interval=self.ticker_interval) + if len(data) == 0: + logger.warning(f"No data found for {self.stake_currency}/USDT") + # Combine the 2 dataframes using close + # this will result in a column named closeETH or closeBTC - depnding on stake_currency. + dataframe = dataframe.merge(data[["date", "close"]], on="date", how="left", suffixes=("", self.config['stake_currency'])) + + # Calculate SMA20 on stakecurrency. Resulting column = smaETH20 + dataframe[f"sma{self.config['stake_currency']}20"] = dataframe[f'close{self.stake_currency}'].rolling(20).mean() + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Based on TA indicators, populates the buy signal for the given dataframe + :param dataframe: DataFrame + :return: DataFrame with buy column + """ + dataframe.loc[ + ( + (dataframe['ema20'] > dataframe['ema50']) & + # stake/USDT above sma(stake/USDT, 20) + (dataframe[f'close{self.stake_currency}'] > dataframe[f'sma{self.stake_currency}20']) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Based on TA indicators, populates the sell signal for the given dataframe + :param dataframe: DataFrame + :return: DataFrame with buy column + """ + dataframe.loc[ + ( + (dataframe['ema20'] < dataframe['ema50']) & + # stake/USDT below sma(stake/USDT, 20) + (dataframe[f'close{self.stake_currency}'] < dataframe[f'sma{self.stake_currency}20']) + ), + 'sell'] = 1 + return dataframe diff --git a/user_data/strategies/Strategy001.py b/user_data/strategies/Strategy001.py index 2c04413..16172d6 100644 --- a/user_data/strategies/Strategy001.py +++ b/user_data/strategies/Strategy001.py @@ -9,10 +9,6 @@ from pandas import DataFrame import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib - -# Update this variable if you change the class name - - class Strategy001(IStrategy): """ Strategy 001 From 41e480fb630a33ab263f8f2ae5237f3999bfe5c4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 15:27:08 +0100 Subject: [PATCH 3/3] Also use real data for dry-run --- user_data/strategies/InformativeSample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_data/strategies/InformativeSample.py b/user_data/strategies/InformativeSample.py index 93256b6..8b93252 100644 --- a/user_data/strategies/InformativeSample.py +++ b/user_data/strategies/InformativeSample.py @@ -89,7 +89,7 @@ class InformativeSample(IStrategy): dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) if self.dp: - if self.dp.runmode == 'live': + if self.dp.runmode in('live', 'dry_run'): # Compare stake-currency with USDT - using the defined ticker-interval if (f"{self.stake_currency}/USDT", self.ticker_interval) in self.dp.available_pairs: data = self.dp.ohlcv(pair='ETH/BTC',