From fb7b65c9094dae1a004601d45abc6220d0f11dc9 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 25 Nov 2018 20:44:40 +0100 Subject: [PATCH 01/28] time in force drafted time in force drafted --- freqtrade/strategy/default_strategy.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/freqtrade/strategy/default_strategy.py b/freqtrade/strategy/default_strategy.py index b282a5938..024b531f4 100644 --- a/freqtrade/strategy/default_strategy.py +++ b/freqtrade/strategy/default_strategy.py @@ -16,10 +16,10 @@ class DefaultStrategy(IStrategy): # Minimal ROI designed for the strategy minimal_roi = { - "40": 0.0, - "30": 0.01, - "20": 0.02, - "0": 0.04 + "40": 0.0, + "30": 0.01, + "20": 0.02, + "0": 0.04 } # Optimal stoploss designed for the strategy @@ -35,6 +35,12 @@ class DefaultStrategy(IStrategy): 'stoploss': 'limit' } + # Optional time in force for orders + order_time_in_force = { + 'buy': 'gtc', + 'sell': 'gtc', + } + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame From 890cef88ab0e9b07ab37550fdc5a0b0257bcab3a Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 25 Nov 2018 21:02:58 +0100 Subject: [PATCH 02/28] oops, lost in git :/ --- freqtrade/freqtradebot.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 602c4ae2f..7a974d385 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -779,10 +779,6 @@ class FreqtradeBot(object): sell_type = 'sell' if sell_reason in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS): sell_type = 'stoploss' - - if self.config.get('dry_run', False) and sell_type == 'stoploss': - limit = trade.stop_loss - # Execute sell and update trade record order_id = self.exchange.sell(pair=str(trade.pair), ordertype=self.strategy.order_types[sell_type], From ba20b1b5c7b259587541a890052219e184df5ec8 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 25 Nov 2018 21:05:25 +0100 Subject: [PATCH 03/28] TIF added to constants and json full --- config_full.json.example | 4 ++++ freqtrade/constants.py | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/config_full.json.example b/config_full.json.example index b0719bcc6..3e7f4bc3b 100644 --- a/config_full.json.example +++ b/config_full.json.example @@ -38,6 +38,10 @@ "sell": "limit", "stoploss": "market" }, + "order_time_in_force": { + "buy": "gtc", + "sell": "gtc", + }, "exchange": { "name": "bittrex", "key": "your_exchange_key", diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 055fee3b2..c6b8519c8 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -15,6 +15,7 @@ DEFAULT_DB_DRYRUN_URL = 'sqlite://' UNLIMITED_STAKE_AMOUNT = 'unlimited' REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss'] ORDERTYPE_POSSIBILITIES = ['limit', 'market'] +ORDERTIF_POSSIBILITIES = ['gtc', 'aon', 'fok', 'ioc'] TICKER_INTERVAL_MINUTES = { @@ -113,6 +114,14 @@ CONF_SCHEMA = { }, 'required': ['buy', 'sell', 'stoploss'] }, + 'order_time_in_force': { + 'type': 'object', + 'properties': { + 'buy': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}, + 'sell': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES} + }, + 'required': ['buy', 'sell'] + }, 'exchange': {'$ref': '#/definitions/exchange'}, 'edge': {'$ref': '#/definitions/edge'}, 'experimental': { From 181424e8ea1d044d8696837291778472319cf8a9 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 25 Nov 2018 21:09:35 +0100 Subject: [PATCH 04/28] time in force validator added --- freqtrade/exchange/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index ae07e36e9..05d6e9c1a 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -103,6 +103,7 @@ class Exchange(object): # Check if all pairs are available self.validate_pairs(config['exchange']['pair_whitelist']) self.validate_ordertypes(config.get('order_types', {})) + self.validate_order_time_in_force(config.get('order_time_in_force', {})) if config.get('ticker_interval'): # Check if timeframe is available self.validate_timeframes(config['ticker_interval']) @@ -227,6 +228,15 @@ class Exchange(object): raise OperationalException( f'Exchange {self.name} does not support market orders.') + def validate_order_time_in_force(self, order_time_in_force: Dict) -> None: + """ + Checks if order time in force configured in strategy/config are supported + """ + if any(v != 'gtc' for k, v in order_time_in_force.items()): + if not self.name == 'Binance': + raise OperationalException( + f'Time in force policies are not supporetd for {self.name} yet.') + def exchange_has(self, endpoint: str) -> bool: """ Checks if exchange implements a specific API endpoint. From 29c23e3136db159cfb00ac96b27c918e5400802b Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 25 Nov 2018 21:38:11 +0100 Subject: [PATCH 05/28] added time in force in buy and sell functions --- freqtrade/exchange/__init__.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 05d6e9c1a..f7801fd02 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -268,7 +268,7 @@ class Exchange(object): price = ceil(big_price) / pow(10, symbol_prec) return price - def buy(self, pair: str, ordertype: str, amount: float, rate: float) -> Dict: + def buy(self, pair: str, ordertype: str, amount: float, rate: float, time_in_force='gtc') -> Dict: if self._conf['dry_run']: order_id = f'dry_run_buy_{randint(0, 10**6)}' self._dry_run_open_orders[order_id] = { @@ -289,7 +289,12 @@ class Exchange(object): amount = self.symbol_amount_prec(pair, amount) rate = self.symbol_price_prec(pair, rate) if ordertype != 'market' else None - return self._api.create_order(pair, ordertype, 'buy', amount, rate) + if time_in_force == 'gtc': + return self._api.create_order(pair, ordertype, 'buy', amount, rate) + else: + return self._api.create_order(pair, ordertype, 'buy', + amount, rate, {'timeInForce': time_in_force}) + except ccxt.InsufficientFunds as e: raise DependencyException( f'Insufficient funds to create limit buy order on market {pair}.' @@ -306,7 +311,8 @@ class Exchange(object): except ccxt.BaseError as e: raise OperationalException(e) - def sell(self, pair: str, ordertype: str, amount: float, rate: float) -> Dict: + def sell(self, pair: str, ordertype: str, amount: float, + rate: float, time_in_force='gtc') -> Dict: if self._conf['dry_run']: order_id = f'dry_run_sell_{randint(0, 10**6)}' self._dry_run_open_orders[order_id] = { @@ -326,7 +332,12 @@ class Exchange(object): amount = self.symbol_amount_prec(pair, amount) rate = self.symbol_price_prec(pair, rate) if ordertype != 'market' else None - return self._api.create_order(pair, ordertype, 'sell', amount, rate) + if time_in_force == 'gtc': + return self._api.create_order(pair, ordertype, 'sell', amount, rate) + else: + return self._api.create_order(pair, ordertype, 'sell', + amount, rate, {'timeInForce': time_in_force}) + except ccxt.InsufficientFunds as e: raise DependencyException( f'Insufficient funds to create limit sell order on market {pair}.' From 962b02b0797895f149b5f3e56d1439b45cbba63f Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 25 Nov 2018 22:02:59 +0100 Subject: [PATCH 06/28] one last step before tests --- freqtrade/constants.py | 1 + freqtrade/freqtradebot.py | 8 ++++++-- freqtrade/resolvers/strategy_resolver.py | 13 +++++++++++++ freqtrade/strategy/interface.py | 6 ++++++ user_data/strategies/test_strategy.py | 8 +++++++- 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index c6b8519c8..0b12343e6 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -14,6 +14,7 @@ DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite' DEFAULT_DB_DRYRUN_URL = 'sqlite://' UNLIMITED_STAKE_AMOUNT = 'unlimited' REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss'] +REQUIRED_ORDERTIF = ['buy', 'sell'] ORDERTYPE_POSSIBILITIES = ['limit', 'market'] ORDERTIF_POSSIBILITIES = ['gtc', 'aon', 'fok', 'ioc'] diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 7a974d385..7258413f1 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -475,7 +475,8 @@ class FreqtradeBot(object): amount = stake_amount / buy_limit order_id = self.exchange.buy(pair=pair, ordertype=self.strategy.order_types['buy'], - amount=amount, rate=buy_limit)['id'] + amount=amount, rate=buy_limit, + time_in_force=self.strategy.order_time_in_force['buy'])['id'] self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, @@ -782,7 +783,10 @@ class FreqtradeBot(object): # Execute sell and update trade record order_id = self.exchange.sell(pair=str(trade.pair), ordertype=self.strategy.order_types[sell_type], - amount=trade.amount, rate=limit)['id'] + amount=trade.amount, rate=limit, + time_in_force=self.strategy.order_time_in_force['sell'] + )['id'] + trade.open_order_id = order_id trade.close_rate_requested = limit trade.sell_reason = sell_reason.value diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 4576d0ec8..c1d967383 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -83,10 +83,23 @@ class StrategyResolver(IResolver): else: config['order_types'] = self.strategy.order_types + if 'order_time_in_force' in config: + self.strategy.order_time_in_force = config['order_time_in_force'] + logger.info( + "Override strategy 'order_time_in_force' with value in config file: %s.", + config['order_time_in_force'] + ) + else: + config['order_time_in_force'] = self.strategy.order_time_in_force + if not all(k in self.strategy.order_types for k in constants.REQUIRED_ORDERTYPES): raise ImportError(f"Impossible to load Strategy '{self.strategy.__class__.__name__}'. " f"Order-types mapping is incomplete.") + if not all(k in self.strategy.order_time_in_force for k in constants.REQUIRED_ORDERTIF): + raise ImportError(f"Impossible to load Strategy '{self.strategy.__class__.__name__}'. " + f"Order-time-in-force mapping is incomplete.") + # Sort and apply type conversions self.strategy.minimal_roi = OrderedDict(sorted( {int(key): value for (key, value) in self.strategy.minimal_roi.items()}.items(), diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 139bcd8be..77abb6a61 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -77,6 +77,12 @@ class IStrategy(ABC): 'stoploss': 'limit' } + # Optional time in force + order_time_in_force: Dict = { + 'buy': 'gtc', + 'sell': 'gtc', + } + # run "populate_indicators" only for new candle process_only_new_candles: bool = False diff --git a/user_data/strategies/test_strategy.py b/user_data/strategies/test_strategy.py index fd2e9ab75..5e0f40d18 100644 --- a/user_data/strategies/test_strategy.py +++ b/user_data/strategies/test_strategy.py @@ -7,7 +7,7 @@ from pandas import DataFrame # Add your lib to import here import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib -import numpy # noqa +import numpy # noqa # This class is a sample. Feel free to customize it. @@ -55,6 +55,12 @@ class TestStrategy(IStrategy): 'stoploss': 'market' } + # Optional order time in force + order_types = { + 'buy': 'gtc', + 'sell': 'gtc' + } + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame From 9f26022ce52044c5d8ec3d228ce1d7a7fea048b7 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 25 Nov 2018 22:08:42 +0100 Subject: [PATCH 07/28] copy/paste corrected --- user_data/strategies/test_strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_data/strategies/test_strategy.py b/user_data/strategies/test_strategy.py index 5e0f40d18..c4db26a5d 100644 --- a/user_data/strategies/test_strategy.py +++ b/user_data/strategies/test_strategy.py @@ -56,7 +56,7 @@ class TestStrategy(IStrategy): } # Optional order time in force - order_types = { + order_time_in_force = { 'buy': 'gtc', 'sell': 'gtc' } From 4ffc74d5facac4ee9243bdf355421de34cdbfe6c Mon Sep 17 00:00:00 2001 From: misagh Date: Tue, 27 Nov 2018 19:05:59 +0100 Subject: [PATCH 08/28] if buy order is rejected or expired the bot should exit the buy loop --- freqtrade/freqtradebot.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 7258413f1..c5edc71ae 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -474,9 +474,21 @@ class FreqtradeBot(object): amount = stake_amount / buy_limit - order_id = self.exchange.buy(pair=pair, ordertype=self.strategy.order_types['buy'], + order = self.exchange.buy(pair=pair, ordertype=self.strategy.order_types['buy'], amount=amount, rate=buy_limit, - time_in_force=self.strategy.order_time_in_force['buy'])['id'] + time_in_force=self.strategy.order_time_in_force['buy']) + order_id = order['id'] + order_info = order['info'] + + # check if order is expired (in case of FOC or IOC orders) + # or rejected by the exchange. + if order_info['status'] == 'EXPIRED' or order_info['status'] == 'REJECTED': + order_type = self.strategy.order_types['buy'] + status = order_info['status'] + logger.warning('Buy %s order for %s is %s by %s.', + order_type, pair_s, status, self.exchange.name) + return False + self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, From 6bedcc5d79b3e71d01f5bcccba7f98cd900e45fe Mon Sep 17 00:00:00 2001 From: misagh Date: Thu, 29 Nov 2018 13:22:41 +0100 Subject: [PATCH 09/28] log enriched for time in force --- freqtrade/freqtradebot.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c5edc71ae..9268341c5 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -484,9 +484,10 @@ class FreqtradeBot(object): # or rejected by the exchange. if order_info['status'] == 'EXPIRED' or order_info['status'] == 'REJECTED': order_type = self.strategy.order_types['buy'] + order_tif = self.strategy.order_time_in_force['buy'] status = order_info['status'] - logger.warning('Buy %s order for %s is %s by %s.', - order_type, pair_s, status, self.exchange.name) + logger.warning('Buy %s order with time in force %s for %s is %s by %s.', + order_tif, order_type, pair_s, status, self.exchange.name) return False From e3876bcf0fadf0465728a262d9382c8c18c077ed Mon Sep 17 00:00:00 2001 From: misagh Date: Tue, 4 Dec 2018 20:36:44 +0100 Subject: [PATCH 10/28] removing AON as it is not supported in binance. will be added once TIF is added for other exchanges --- freqtrade/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 31c3fe9a9..4c3b86e7e 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -16,7 +16,7 @@ UNLIMITED_STAKE_AMOUNT = 'unlimited' REQUIRED_ORDERTIF = ['buy', 'sell'] REQUIRED_ORDERTYPES = ['buy', 'sell', 'stoploss', 'stoploss_on_exchange'] ORDERTYPE_POSSIBILITIES = ['limit', 'market'] -ORDERTIF_POSSIBILITIES = ['gtc', 'aon', 'fok', 'ioc'] +ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] TICKER_INTERVAL_MINUTES = { From 910601ba1d6e1af9201369859eda2502247149f0 Mon Sep 17 00:00:00 2001 From: misagh Date: Tue, 4 Dec 2018 20:50:35 +0100 Subject: [PATCH 11/28] =?UTF-8?q?in=20case=20exchange=20doesn=E2=80=99t=20?= =?UTF-8?q?return=20order=20info=20=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index ff73a036f..7894fc6cf 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -447,11 +447,11 @@ class FreqtradeBot(object): amount=amount, rate=buy_limit, time_in_force=self.strategy.order_time_in_force['buy']) order_id = order['id'] - order_info = order['info'] + order_info = order.get('info', {}) # check if order is expired (in case of FOC or IOC orders) # or rejected by the exchange. - if order_info['status'] == 'EXPIRED' or order_info['status'] == 'REJECTED': + if order_info.get('status', '') == 'EXPIRED' or order_info.get('status', '') == 'REJECTED': order_type = self.strategy.order_types['buy'] order_tif = self.strategy.order_time_in_force['buy'] status = order_info['status'] From d12cc39a5ec8f192992fac6fb14c78c31159cad0 Mon Sep 17 00:00:00 2001 From: misagh Date: Tue, 4 Dec 2018 20:59:55 +0100 Subject: [PATCH 12/28] some visual happyness --- freqtrade/exchange/__init__.py | 3 ++- freqtrade/freqtradebot.py | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index ce638e042..727766d0f 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -275,7 +275,8 @@ class Exchange(object): price = ceil(big_price) / pow(10, symbol_prec) return price - def buy(self, pair: str, ordertype: str, amount: float, rate: float, time_in_force='gtc') -> Dict: + def buy(self, pair: str, ordertype: str, amount: float, + rate: float, time_in_force='gtc') -> Dict: if self._conf['dry_run']: order_id = f'dry_run_buy_{randint(0, 10**6)}' self._dry_run_open_orders[order_id] = { diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 7894fc6cf..52d4b88ec 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -444,14 +444,15 @@ class FreqtradeBot(object): amount = stake_amount / buy_limit order = self.exchange.buy(pair=pair, ordertype=self.strategy.order_types['buy'], - amount=amount, rate=buy_limit, - time_in_force=self.strategy.order_time_in_force['buy']) + amount=amount, rate=buy_limit, + time_in_force=self.strategy.order_time_in_force['buy']) order_id = order['id'] order_info = order.get('info', {}) # check if order is expired (in case of FOC or IOC orders) # or rejected by the exchange. - if order_info.get('status', '') == 'EXPIRED' or order_info.get('status', '') == 'REJECTED': + order_status = order_info.get('status', '') + if order_status == 'EXPIRED' or order_status == 'REJECTED': order_type = self.strategy.order_types['buy'] order_tif = self.strategy.order_time_in_force['buy'] status = order_info['status'] @@ -459,7 +460,6 @@ class FreqtradeBot(object): order_tif, order_type, pair_s, status, self.exchange.name) return False - self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, 'exchange': self.exchange.name.capitalize(), From b35199a772f4d786179fe811a358ed903f55fabc Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 9 Dec 2018 15:59:05 +0100 Subject: [PATCH 13/28] intermediary commit before extracting the logic --- freqtrade/freqtradebot.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 907734313..9a7975e17 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -367,6 +367,7 @@ class FreqtradeBot(object): pair_url = self.exchange.get_pair_detail_url(pair) stake_currency = self.config['stake_currency'] fiat_currency = self.config.get('fiat_display_currency', None) + time_in_force = self.strategy.order_time_in_force['buy'] if price: buy_limit = price @@ -386,20 +387,29 @@ class FreqtradeBot(object): order = self.exchange.buy(pair=pair, ordertype=self.strategy.order_types['buy'], amount=amount, rate=buy_limit, - time_in_force=self.strategy.order_time_in_force['buy']) + time_in_force=time_in_force) order_id = order['id'] - order_info = order.get('info', {}) + order_status = order.get('status', None) - # check if order is expired (in case of FOC or IOC orders) - # or rejected by the exchange. - order_status = order_info.get('status', '') - if order_status == 'EXPIRED' or order_status == 'REJECTED': + # in case of FOK or IOC orders we can check immediately + # if the order is fulfilled fully or partially + if order_status == 'expired' or order_status == 'rejected': order_type = self.strategy.order_types['buy'] order_tif = self.strategy.order_time_in_force['buy'] - status = order_info['status'] - logger.warning('Buy %s order with time in force %s for %s is %s by %s.', - order_tif, order_type, pair_s, status, self.exchange.name) - return False + + # return false is order is not filled + if float(order['filled']) == 0: + logger.warning('Buy %s order with time in force %s for %s is %s by %s.' + ' zero amount is fulfilled.', + order_tif, order_type, pair_s, order_status, self.exchange.name) + return False + else: # the order is partially fulfilled + logger.warning('Buy %s order with time in force %s for %s is %s by %s.' + ' %s amount fulfilled out of %s (%s remaining which is canceled).', + order_tif, order_type, pair_s, order_status, self.exchange.name, + order['filled'], order['amount'], order['remaining'] + ) + self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, From 2f5c8941ebbd6a1ca34d5bdd3939494e33af08f2 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 9 Dec 2018 16:00:04 +0100 Subject: [PATCH 14/28] removing unnecessary default value --- freqtrade/exchange/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 727766d0f..85abf2939 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -276,7 +276,7 @@ class Exchange(object): return price def buy(self, pair: str, ordertype: str, amount: float, - rate: float, time_in_force='gtc') -> Dict: + rate: float, time_in_force) -> Dict: if self._conf['dry_run']: order_id = f'dry_run_buy_{randint(0, 10**6)}' self._dry_run_open_orders[order_id] = { From 20d794e2658b062e1995313621aa0e6f33274d12 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 9 Dec 2018 16:04:28 +0100 Subject: [PATCH 15/28] mistake in previous commit --- freqtrade/optimize/edge_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/edge_cli.py b/freqtrade/optimize/edge_cli.py index fbe81812d..a2189f6c1 100644 --- a/freqtrade/optimize/edge_cli.py +++ b/freqtrade/optimize/edge_cli.py @@ -55,7 +55,7 @@ class EdgeCli(object): 'average duration (min)'] for result in results.items(): - if result[1].nb_trades > 0 and result[1].winrate > 0.60: + if result[1].nb_trades > 0: tabular_data.append([ result[0], result[1].stoploss, From 663e33d2efc389f51870054fb9e3a2e17622518a Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 9 Dec 2018 16:06:00 +0100 Subject: [PATCH 16/28] if condition refactored --- freqtrade/exchange/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 85abf2939..e9d819beb 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -240,7 +240,7 @@ class Exchange(object): Checks if order time in force configured in strategy/config are supported """ if any(v != 'gtc' for k, v in order_time_in_force.items()): - if not self.name == 'Binance': + if self.name is not 'Binance': raise OperationalException( f'Time in force policies are not supporetd for {self.name} yet.') From 866b7aee8ec2ec964bf14eab7a8aedbe2f9d38c1 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 9 Dec 2018 16:22:21 +0100 Subject: [PATCH 17/28] tests fixed --- freqtrade/freqtradebot.py | 4 ++-- freqtrade/tests/exchange/test_exchange.py | 27 +++++++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 9a7975e17..3a124568e 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -403,13 +403,13 @@ class FreqtradeBot(object): ' zero amount is fulfilled.', order_tif, order_type, pair_s, order_status, self.exchange.name) return False - else: # the order is partially fulfilled + else: # the order is partially fulfilled logger.warning('Buy %s order with time in force %s for %s is %s by %s.' ' %s amount fulfilled out of %s (%s remaining which is canceled).', order_tif, order_type, pair_s, order_status, self.exchange.name, order['filled'], order['amount'], order['remaining'] ) - + return False self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index d1f391266..e021b2de8 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -426,7 +426,8 @@ def test_buy_dry_run(default_conf, mocker): default_conf['dry_run'] = True exchange = get_patched_exchange(mocker, default_conf) - order = exchange.buy(pair='ETH/BTC', ordertype='limit', amount=1, rate=200) + order = exchange.buy(pair='ETH/BTC', ordertype='limit', + amount=1, rate=200, time_in_force='gtc') assert 'id' in order assert 'dry_run_buy_' in order['id'] @@ -435,6 +436,7 @@ def test_buy_prod(default_conf, mocker): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) order_type = 'market' + time_in_force = 'gtc' api_mock.create_order = MagicMock(return_value={ 'id': order_id, 'info': { @@ -446,7 +448,9 @@ def test_buy_prod(default_conf, mocker): mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) exchange = get_patched_exchange(mocker, default_conf, api_mock) - order = exchange.buy(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) + order = exchange.buy(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) + assert 'id' in order assert 'info' in order assert order['id'] == order_id @@ -458,7 +462,12 @@ def test_buy_prod(default_conf, mocker): api_mock.create_order.reset_mock() order_type = 'limit' - order = exchange.buy(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) + order = exchange.buy( + pair='ETH/BTC', + ordertype=order_type, + amount=1, + rate=200, + time_in_force=time_in_force) assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' assert api_mock.create_order.call_args[0][1] == order_type assert api_mock.create_order.call_args[0][2] == 'buy' @@ -469,22 +478,26 @@ def test_buy_prod(default_conf, mocker): with pytest.raises(DependencyException): api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds) exchange = get_patched_exchange(mocker, default_conf, api_mock) - exchange.buy(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) + exchange.buy(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) with pytest.raises(DependencyException): api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder) exchange = get_patched_exchange(mocker, default_conf, api_mock) - exchange.buy(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) + exchange.buy(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) with pytest.raises(TemporaryError): api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError) exchange = get_patched_exchange(mocker, default_conf, api_mock) - exchange.buy(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) + exchange.buy(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) with pytest.raises(OperationalException): api_mock.create_order = MagicMock(side_effect=ccxt.BaseError) exchange = get_patched_exchange(mocker, default_conf, api_mock) - exchange.buy(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200) + exchange.buy(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) def test_sell_dry_run(default_conf, mocker): From 6018f2d252e6f22bd4464c814fe6b2fde48a5c7e Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 10 Dec 2018 18:52:24 +0100 Subject: [PATCH 18/28] order status handled in case of IOC and FOK --- freqtrade/freqtradebot.py | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3a124568e..7adc4fa27 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -370,12 +370,12 @@ class FreqtradeBot(object): time_in_force = self.strategy.order_time_in_force['buy'] if price: - buy_limit = price + buy_limit_requested = price else: # Calculate amount - buy_limit = self.get_target_bid(pair, self.exchange.get_ticker(pair)) + buy_limit_requested = self.get_target_bid(pair, self.exchange.get_ticker(pair)) - min_stake_amount = self._get_min_pair_stake_amount(pair_s, buy_limit) + min_stake_amount = self._get_min_pair_stake_amount(pair_s, buy_limit_requested) if min_stake_amount is not None and min_stake_amount > stake_amount: logger.warning( f'Can\'t open a new trade for {pair_s}: stake amount' @@ -383,16 +383,17 @@ class FreqtradeBot(object): ) return False - amount = stake_amount / buy_limit + amount = stake_amount / buy_limit_requested order = self.exchange.buy(pair=pair, ordertype=self.strategy.order_types['buy'], - amount=amount, rate=buy_limit, + amount=amount, rate=buy_limit_requested, time_in_force=time_in_force) order_id = order['id'] order_status = order.get('status', None) - # in case of FOK or IOC orders we can check immediately - # if the order is fulfilled fully or partially + # we assume the order is executed at the price requested + buy_limit_filled_price = buy_limit_requested + if order_status == 'expired' or order_status == 'rejected': order_type = self.strategy.order_types['buy'] order_tif = self.strategy.order_time_in_force['buy'] @@ -403,20 +404,33 @@ class FreqtradeBot(object): ' zero amount is fulfilled.', order_tif, order_type, pair_s, order_status, self.exchange.name) return False - else: # the order is partially fulfilled + else: + # the order is partially fulfilled + # in case of IOC orders we can check immediately + # if the order is fulfilled fully or partially logger.warning('Buy %s order with time in force %s for %s is %s by %s.' ' %s amount fulfilled out of %s (%s remaining which is canceled).', order_tif, order_type, pair_s, order_status, self.exchange.name, order['filled'], order['amount'], order['remaining'] ) - return False + stake_amount = order['price'] + amount = order['amount'] + buy_limit_filled_price = order['average'] + order_id = None + + # in case of FOK the order may be filled immediately and fully + elif order_status == 'filled': + stake_amount = order['price'] + amount = order['amount'] + buy_limit_filled_price = order['average'] + order_id = None self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, 'exchange': self.exchange.name.capitalize(), 'pair': pair_s, 'market_url': pair_url, - 'limit': buy_limit, + 'limit': buy_limit_requested, 'stake_amount': stake_amount, 'stake_currency': stake_currency, 'fiat_currency': fiat_currency @@ -430,8 +444,8 @@ class FreqtradeBot(object): amount=amount, fee_open=fee, fee_close=fee, - open_rate=buy_limit, - open_rate_requested=buy_limit, + open_rate=buy_limit_filled_price, + open_rate_requested=buy_limit_requested, open_date=datetime.utcnow(), exchange=self.exchange.id, open_order_id=order_id, From e6fd7da43f65ccde9977970a9d1e9f177d62bed4 Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 10 Dec 2018 19:09:20 +0100 Subject: [PATCH 19/28] adding test: create order should consider TIF --- freqtrade/tests/exchange/test_exchange.py | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index e021b2de8..02314b32c 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -500,6 +500,36 @@ def test_buy_prod(default_conf, mocker): amount=1, rate=200, time_in_force=time_in_force) +def test_buy_considers_time_in_force(default_conf, mocker): + api_mock = MagicMock() + order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) + order_type = 'market' + time_in_force = 'ioc' + api_mock.create_order = MagicMock(return_value={ + 'id': order_id, + 'info': { + 'foo': 'bar' + } + }) + default_conf['dry_run'] = False + mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y) + mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y) + exchange = get_patched_exchange(mocker, default_conf, api_mock) + + order = exchange.buy(pair='ETH/BTC', ordertype=order_type, + amount=1, rate=200, time_in_force=time_in_force) + + assert 'id' in order + assert 'info' in order + assert order['id'] == order_id + assert api_mock.create_order.call_args[0][0] == 'ETH/BTC' + assert api_mock.create_order.call_args[0][1] == order_type + assert api_mock.create_order.call_args[0][2] == 'buy' + assert api_mock.create_order.call_args[0][3] == 1 + assert api_mock.create_order.call_args[0][4] is None + assert api_mock.create_order.call_args[0][5] == {'timeInForce': 'ioc'} + + def test_sell_dry_run(default_conf, mocker): default_conf['dry_run'] = True exchange = get_patched_exchange(mocker, default_conf) From adcaa8439e37f192d6f0e1d91d4ebdf3cabc1972 Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 10 Dec 2018 19:17:56 +0100 Subject: [PATCH 20/28] test_strategy_override_order_tif added --- freqtrade/tests/strategy/test_strategy.py | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index 271fe4d32..08d95fc5d 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -221,6 +221,41 @@ def test_strategy_override_order_types(caplog): StrategyResolver(config) +def test_strategy_override_order_tif(caplog): + caplog.set_level(logging.INFO) + + order_time_in_force = { + 'buy': 'fok', + 'sell': 'gtc', + } + + config = { + 'strategy': 'DefaultStrategy', + 'order_time_in_force': order_time_in_force + } + resolver = StrategyResolver(config) + + assert resolver.strategy.order_time_in_force + for method in ['buy', 'sell']: + assert resolver.strategy.order_time_in_force[method] == order_time_in_force[method] + + assert ('freqtrade.resolvers.strategy_resolver', + logging.INFO, + "Override strategy 'order_time_in_force' with value in config file:" + " {'buy': 'fok', 'sell': 'gtc'}." + ) in caplog.record_tuples + + config = { + 'strategy': 'DefaultStrategy', + 'order_time_in_force': {'buy': 'fok'} + } + # Raise error for invalid configuration + with pytest.raises(ImportError, + match=r"Impossible to load Strategy 'DefaultStrategy'. " + r"Order-time-in-force mapping is incomplete."): + StrategyResolver(config) + + def test_deprecate_populate_indicators(result): default_location = path.join(path.dirname(path.realpath(__file__))) resolver = StrategyResolver({'strategy': 'TestStrategyLegacy', From 8d8b53f4d1a6fad07dbf4d6931f2f5f855f4f802 Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 12 Dec 2018 13:05:55 +0100 Subject: [PATCH 21/28] added tests for IOC and FOK --- freqtrade/freqtradebot.py | 10 +++---- freqtrade/tests/test_freqtradebot.py | 44 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 7adc4fa27..099c62591 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -413,16 +413,16 @@ class FreqtradeBot(object): order_tif, order_type, pair_s, order_status, self.exchange.name, order['filled'], order['amount'], order['remaining'] ) - stake_amount = order['price'] + stake_amount = order['cost'] amount = order['amount'] - buy_limit_filled_price = order['average'] + buy_limit_filled_price = order['price'] order_id = None # in case of FOK the order may be filled immediately and fully - elif order_status == 'filled': - stake_amount = order['price'] + elif order_status == 'closed': + stake_amount = order['cost'] amount = order['amount'] - buy_limit_filled_price = order['average'] + buy_limit_filled_price = order['price'] order_id = None self.rpc.send_msg({ diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 70cf8edc5..0b6a14112 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -863,6 +863,13 @@ def test_execute_buy(mocker, default_conf, fee, markets, limit_buy_order) -> Non assert call_args['rate'] == bid assert call_args['amount'] == stake_amount / bid + # Should create an open trade with an open order id + # As the order is not fulfilled yet + trade = Trade.query.first() + assert trade + assert trade.is_open is True + assert trade.open_order_id == limit_buy_order['id'] + # Test calling with price fix_price = 0.06 assert freqtrade.execute_buy(pair, stake_amount, fix_price) @@ -875,6 +882,43 @@ def test_execute_buy(mocker, default_conf, fee, markets, limit_buy_order) -> Non assert call_args['rate'] == fix_price assert call_args['amount'] == stake_amount / fix_price + # In case of closed order + limit_buy_order['status'] = 'closed' + limit_buy_order['price'] = 10 + limit_buy_order['cost'] = 100 + mocker.patch('freqtrade.exchange.Exchange.buy', MagicMock(return_value=limit_buy_order)) + assert freqtrade.execute_buy(pair, stake_amount) + trade = Trade.query.all()[2] + assert trade + assert trade.open_order_id is None + assert trade.open_rate == 10 + assert trade.stake_amount == 100 + + # In case of rejected or expired order and partially filled + limit_buy_order['status'] = 'expired' + limit_buy_order['amount'] = 90.99181073 + limit_buy_order['filled'] = 80.99181073 + limit_buy_order['remaining'] = 10.00 + limit_buy_order['price'] = 0.5 + limit_buy_order['cost'] = 40.495905365 + mocker.patch('freqtrade.exchange.Exchange.buy', MagicMock(return_value=limit_buy_order)) + assert freqtrade.execute_buy(pair, stake_amount) + trade = Trade.query.all()[3] + assert trade + assert trade.open_order_id is None + assert trade.open_rate == 0.5 + assert trade.stake_amount == 40.495905365 + + # In case of the order is rejected and not filled at all + limit_buy_order['status'] = 'rejected' + limit_buy_order['amount'] = 90.99181073 + limit_buy_order['filled'] = 0.0 + limit_buy_order['remaining'] = 90.99181073 + limit_buy_order['price'] = 0.5 + limit_buy_order['cost'] = 0.0 + mocker.patch('freqtrade.exchange.Exchange.buy', MagicMock(return_value=limit_buy_order)) + assert not freqtrade.execute_buy(pair, stake_amount) + def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order) -> None: patch_RPCManager(mocker) From aa1262bea6fe0bb55e3c20289ef0d9b9bb65a5c8 Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 12 Dec 2018 13:33:03 +0100 Subject: [PATCH 22/28] typo corrected --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 099c62591..8e0440dc3 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -398,7 +398,7 @@ class FreqtradeBot(object): order_type = self.strategy.order_types['buy'] order_tif = self.strategy.order_time_in_force['buy'] - # return false is order is not filled + # return false if the order is not filled if float(order['filled']) == 0: logger.warning('Buy %s order with time in force %s for %s is %s by %s.' ' zero amount is fulfilled.', @@ -430,7 +430,7 @@ class FreqtradeBot(object): 'exchange': self.exchange.name.capitalize(), 'pair': pair_s, 'market_url': pair_url, - 'limit': buy_limit_requested, + 'limit': buy_limit_filled_price, 'stake_amount': stake_amount, 'stake_currency': stake_currency, 'fiat_currency': fiat_currency From 9d8a3b4ec5ca30ecfe6ff23d05ca0f7aacd386ab Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 16 Dec 2018 22:02:29 +0100 Subject: [PATCH 23/28] docs added --- docs/configuration.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index c4c0bed28..4db6c2e70 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -40,6 +40,7 @@ The table below will list all configuration parameters. | `ask_strategy.order_book_min` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `ask_strategy.order_book_max` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `order_types` | None | No | Configure order-types depending on the action (`"buy"`, `"sell"`, `"stoploss"`, `"stoploss_on_exchange"`). +| `order_time_in_force` | None | No | Configure time in force for buy and sell orders (`"buy"`, `"sell"`). [More info blow](#user-content-understand-order-time_in_force). | `exchange.name` | bittrex | Yes | Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). | `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode. | `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode. @@ -161,6 +162,25 @@ The below is the default which is used if this is not configured in either Strat **NOTE**: Not all exchanges support "market" orders. The following message will be shown if your exchange does not support market orders: `"Exchange does not support market orders."` +### Understand order_time_in_force +Order time in force defines the policy by which the order is executed on the exchange. Three commonly used time in force are:
+`GTC (Goog Till Canceled):` +This is most of the time the default time in force. It means the order will remain on exchange till it is canceled by user. It can be fully or partially fulfilled. If partially fulfilled, the remaining will stay on the exchange till cancelled.
+`FOK (Full Or Kill):` +It means if the order is not executed immediately AND fully then it is canceled by the exchange.
+`IOC (Immediate Or Canceled):` +It is the same as FOK (above) except it can be partially fulfilled. The remaining part is automatically cancelled by the exchange. +
+`order_time_in_force` contains a dict buy and sell time in force policy. This can be set in the configuration or in the strategy. Configuration overwrites strategy configurations.
+possible values are: `gtc` (defaul), `fok` or `ioc`.
+``` python + "order_time_in_force": { + "buy": "gtc", + "sell": "gtc" + }, +``` +**NOTE**: This is an ongoing work. For now it is supported only for binance and only for buy orders. Please don't change the default value unless you know what you are doing.
+ ### What values for exchange.name? Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports 115 cryptocurrency @@ -215,7 +235,7 @@ production mode. ### Dynamic Pairlists -Dynamic pairlists select pairs for you based on the logic configured. +Dynamic pairlists select pairs for you based on the logic configured. The bot runs against all pairs (with that stake) on the exchange, and a number of assets (`number_assets`) is selected based on the selected criteria. By *default*, a Static Pairlist is used (configured as `"pair_whitelist"` under the `"exchange"` section of this configuration). From a967b8918a70c803e474e4f4f036d9ecf96582ed Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 16 Dec 2018 22:05:15 +0100 Subject: [PATCH 24/28] broken link corrected --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 4db6c2e70..3ef39127a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -40,7 +40,7 @@ The table below will list all configuration parameters. | `ask_strategy.order_book_min` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `ask_strategy.order_book_max` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `order_types` | None | No | Configure order-types depending on the action (`"buy"`, `"sell"`, `"stoploss"`, `"stoploss_on_exchange"`). -| `order_time_in_force` | None | No | Configure time in force for buy and sell orders (`"buy"`, `"sell"`). [More info blow](#user-content-understand-order-time_in_force). +| `order_time_in_force` | None | No | Configure time in force for buy and sell orders (`"buy"`, `"sell"`). [More informatin below](#understand-order_time_in_force). | `exchange.name` | bittrex | Yes | Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). | `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode. | `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode. From 2e7028442d08b91059c3e7b4b86a87ff500f6d34 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 16 Dec 2018 22:07:03 +0100 Subject: [PATCH 25/28] reformatting --- docs/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 3ef39127a..66572b446 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -164,11 +164,11 @@ The following message will be shown if your exchange does not support market ord ### Understand order_time_in_force Order time in force defines the policy by which the order is executed on the exchange. Three commonly used time in force are:
-`GTC (Goog Till Canceled):` +**GTC (Goog Till Canceled):** This is most of the time the default time in force. It means the order will remain on exchange till it is canceled by user. It can be fully or partially fulfilled. If partially fulfilled, the remaining will stay on the exchange till cancelled.
-`FOK (Full Or Kill):` +**FOK (Full Or Kill):** It means if the order is not executed immediately AND fully then it is canceled by the exchange.
-`IOC (Immediate Or Canceled):` +**IOC (Immediate Or Canceled):** It is the same as FOK (above) except it can be partially fulfilled. The remaining part is automatically cancelled by the exchange.
`order_time_in_force` contains a dict buy and sell time in force policy. This can be set in the configuration or in the strategy. Configuration overwrites strategy configurations.
From f756f1ad28a1ee9f856b8cd20659249ef7063d42 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 16 Dec 2018 22:08:50 +0100 Subject: [PATCH 26/28] unnecessary explanation removed. --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 66572b446..9b2860988 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -40,7 +40,7 @@ The table below will list all configuration parameters. | `ask_strategy.order_book_min` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `ask_strategy.order_book_max` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `order_types` | None | No | Configure order-types depending on the action (`"buy"`, `"sell"`, `"stoploss"`, `"stoploss_on_exchange"`). -| `order_time_in_force` | None | No | Configure time in force for buy and sell orders (`"buy"`, `"sell"`). [More informatin below](#understand-order_time_in_force). +| `order_time_in_force` | None | No | Configure time in force for buy and sell orders. [More informatin below](#understand-order_time_in_force). | `exchange.name` | bittrex | Yes | Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). | `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode. | `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode. From 213155e6d394e64fe488e57eb9706c0879b1d3c0 Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 16 Dec 2018 22:09:46 +0100 Subject: [PATCH 27/28] typo --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 9b2860988..bd36688a8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -172,7 +172,7 @@ It means if the order is not executed immediately AND fully then it is canceled It is the same as FOK (above) except it can be partially fulfilled. The remaining part is automatically cancelled by the exchange.
`order_time_in_force` contains a dict buy and sell time in force policy. This can be set in the configuration or in the strategy. Configuration overwrites strategy configurations.
-possible values are: `gtc` (defaul), `fok` or `ioc`.
+possible values are: `gtc` (default), `fok` or `ioc`.
``` python "order_time_in_force": { "buy": "gtc", From c784b829e5a8ae6e4c9215bf7ce0a1da7e41976c Mon Sep 17 00:00:00 2001 From: misagh Date: Sun, 16 Dec 2018 22:11:51 +0100 Subject: [PATCH 28/28] typo --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index bd36688a8..521f330ec 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -40,7 +40,7 @@ The table below will list all configuration parameters. | `ask_strategy.order_book_min` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `ask_strategy.order_book_max` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `order_types` | None | No | Configure order-types depending on the action (`"buy"`, `"sell"`, `"stoploss"`, `"stoploss_on_exchange"`). -| `order_time_in_force` | None | No | Configure time in force for buy and sell orders. [More informatin below](#understand-order_time_in_force). +| `order_time_in_force` | None | No | Configure time in force for buy and sell orders. [More information below](#understand-order_time_in_force). | `exchange.name` | bittrex | Yes | Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). | `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode. | `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode.