Merge pull request #3676 from freqtrade/stoploss_remove_unused_argument
[minor] Cleanup and exception hierarchy documentation
This commit is contained in:
commit
22f6e884ed
@ -85,6 +85,35 @@ docker-compose exec freqtrade_develop /bin/bash
|
|||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/419355/65456522-ba671a80-de06-11e9-9598-df9ca0d8dcac.png)
|
![image](https://user-images.githubusercontent.com/419355/65456522-ba671a80-de06-11e9-9598-df9ca0d8dcac.png)
|
||||||
|
|
||||||
|
## ErrorHandling
|
||||||
|
|
||||||
|
Freqtrade Exceptions all inherit from `FreqtradeException`.
|
||||||
|
This general class of error should however not be used directly. Instead, multiple specialized sub-Exceptions exist.
|
||||||
|
|
||||||
|
Below is an outline of exception inheritance hierarchy:
|
||||||
|
|
||||||
|
```
|
||||||
|
+ FreqtradeException
|
||||||
|
|
|
||||||
|
+---+ OperationalException
|
||||||
|
|
|
||||||
|
+---+ DependencyException
|
||||||
|
| |
|
||||||
|
| +---+ PricingError
|
||||||
|
| |
|
||||||
|
| +---+ ExchangeError
|
||||||
|
| |
|
||||||
|
| +---+ TemporaryError
|
||||||
|
| |
|
||||||
|
| +---+ DDosProtection
|
||||||
|
| |
|
||||||
|
| +---+ InvalidOrderException
|
||||||
|
| |
|
||||||
|
| +---+ RetryableOrderError
|
||||||
|
|
|
||||||
|
+---+ StrategyError
|
||||||
|
```
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
### Dynamic Pairlist
|
### Dynamic Pairlist
|
||||||
|
@ -29,7 +29,14 @@ class PricingError(DependencyException):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class InvalidOrderException(FreqtradeException):
|
class ExchangeError(DependencyException):
|
||||||
|
"""
|
||||||
|
Error raised out of the exchange.
|
||||||
|
Has multiple Errors to determine the appropriate error.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidOrderException(ExchangeError):
|
||||||
"""
|
"""
|
||||||
This is returned when the order is not valid. Example:
|
This is returned when the order is not valid. Example:
|
||||||
If stoploss on exchange order is hit, then trying to cancel the order
|
If stoploss on exchange order is hit, then trying to cancel the order
|
||||||
@ -44,13 +51,6 @@ class RetryableOrderError(InvalidOrderException):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ExchangeError(DependencyException):
|
|
||||||
"""
|
|
||||||
Error raised out of the exchange.
|
|
||||||
Has multiple Errors to determine the appropriate error.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class TemporaryError(ExchangeError):
|
class TemporaryError(ExchangeError):
|
||||||
"""
|
"""
|
||||||
Temporary network or exchange related error.
|
Temporary network or exchange related error.
|
||||||
|
@ -975,7 +975,7 @@ class Exchange:
|
|||||||
except ccxt.BaseError as e:
|
except ccxt.BaseError as e:
|
||||||
raise OperationalException(e) from e
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
# Assign method to fetch_stoploss_order to allow easy overriding in other classes
|
# Assign method to cancel_stoploss_order to allow easy overriding in other classes
|
||||||
cancel_stoploss_order = cancel_order
|
cancel_stoploss_order = cancel_order
|
||||||
|
|
||||||
def is_cancel_order_result_suitable(self, corder) -> bool:
|
def is_cancel_order_result_suitable(self, corder) -> bool:
|
||||||
@ -1041,10 +1041,10 @@ class Exchange:
|
|||||||
@retrier
|
@retrier
|
||||||
def fetch_l2_order_book(self, pair: str, limit: int = 100) -> dict:
|
def fetch_l2_order_book(self, pair: str, limit: int = 100) -> dict:
|
||||||
"""
|
"""
|
||||||
get order book level 2 from exchange
|
Get L2 order book from exchange.
|
||||||
|
Can be limited to a certain amount (if supported).
|
||||||
Notes:
|
Returns a dict in the format
|
||||||
20180619: bittrex doesnt support limits -.-
|
{'asks': [price, volume], 'bids': [price, volume]}
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
@ -770,7 +770,7 @@ class FreqtradeBot:
|
|||||||
logger.debug('Found no sell signal for %s.', trade)
|
logger.debug('Found no sell signal for %s.', trade)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create_stoploss_order(self, trade: Trade, stop_price: float, rate: float) -> bool:
|
def create_stoploss_order(self, trade: Trade, stop_price: float) -> bool:
|
||||||
"""
|
"""
|
||||||
Abstracts creating stoploss orders from the logic.
|
Abstracts creating stoploss orders from the logic.
|
||||||
Handles errors and updates the trade database object.
|
Handles errors and updates the trade database object.
|
||||||
@ -833,14 +833,13 @@ class FreqtradeBot:
|
|||||||
stoploss = self.edge.stoploss(pair=trade.pair) if self.edge else self.strategy.stoploss
|
stoploss = self.edge.stoploss(pair=trade.pair) if self.edge else self.strategy.stoploss
|
||||||
stop_price = trade.open_rate * (1 + stoploss)
|
stop_price = trade.open_rate * (1 + stoploss)
|
||||||
|
|
||||||
if self.create_stoploss_order(trade=trade, stop_price=stop_price, rate=stop_price):
|
if self.create_stoploss_order(trade=trade, stop_price=stop_price):
|
||||||
trade.stoploss_last_update = datetime.now()
|
trade.stoploss_last_update = datetime.now()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If stoploss order is canceled for some reason we add it
|
# If stoploss order is canceled for some reason we add it
|
||||||
if stoploss_order and stoploss_order['status'] in ('canceled', 'cancelled'):
|
if stoploss_order and stoploss_order['status'] in ('canceled', 'cancelled'):
|
||||||
if self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss,
|
if self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss):
|
||||||
rate=trade.stop_loss):
|
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
trade.stoploss_order_id = None
|
trade.stoploss_order_id = None
|
||||||
@ -877,8 +876,7 @@ class FreqtradeBot:
|
|||||||
f"for pair {trade.pair}")
|
f"for pair {trade.pair}")
|
||||||
|
|
||||||
# Create new stoploss order
|
# Create new stoploss order
|
||||||
if not self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss,
|
if not self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss):
|
||||||
rate=trade.stop_loss):
|
|
||||||
logger.warning(f"Could not create trailing stoploss order "
|
logger.warning(f"Could not create trailing stoploss order "
|
||||||
f"for pair {trade.pair}.")
|
f"for pair {trade.pair}.")
|
||||||
|
|
||||||
@ -923,7 +921,7 @@ class FreqtradeBot:
|
|||||||
if not trade.open_order_id:
|
if not trade.open_order_id:
|
||||||
continue
|
continue
|
||||||
order = self.exchange.fetch_order(trade.open_order_id, trade.pair)
|
order = self.exchange.fetch_order(trade.open_order_id, trade.pair)
|
||||||
except (ExchangeError, InvalidOrderException):
|
except (ExchangeError):
|
||||||
logger.info('Cannot query order for %s due to %s', trade, traceback.format_exc())
|
logger.info('Cannot query order for %s due to %s', trade, traceback.format_exc())
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -956,7 +954,7 @@ class FreqtradeBot:
|
|||||||
for trade in Trade.get_open_order_trades():
|
for trade in Trade.get_open_order_trades():
|
||||||
try:
|
try:
|
||||||
order = self.exchange.fetch_order(trade.open_order_id, trade.pair)
|
order = self.exchange.fetch_order(trade.open_order_id, trade.pair)
|
||||||
except (DependencyException, InvalidOrderException):
|
except (ExchangeError):
|
||||||
logger.info('Cannot query order for %s due to %s', trade, traceback.format_exc())
|
logger.info('Cannot query order for %s due to %s', trade, traceback.format_exc())
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
|||||||
import arrow
|
import arrow
|
||||||
from numpy import NAN, mean
|
from numpy import NAN, mean
|
||||||
|
|
||||||
from freqtrade.exceptions import (ExchangeError, InvalidOrderException,
|
from freqtrade.exceptions import (ExchangeError,
|
||||||
PricingError)
|
PricingError)
|
||||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
|
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
|
||||||
from freqtrade.misc import shorten_date
|
from freqtrade.misc import shorten_date
|
||||||
@ -555,7 +555,7 @@ class RPC:
|
|||||||
try:
|
try:
|
||||||
self._freqtrade.exchange.cancel_order(trade.open_order_id, trade.pair)
|
self._freqtrade.exchange.cancel_order(trade.open_order_id, trade.pair)
|
||||||
c_count += 1
|
c_count += 1
|
||||||
except (ExchangeError, InvalidOrderException):
|
except (ExchangeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# cancel stoploss on exchange ...
|
# cancel stoploss on exchange ...
|
||||||
@ -565,7 +565,7 @@ class RPC:
|
|||||||
self._freqtrade.exchange.cancel_stoploss_order(trade.stoploss_order_id,
|
self._freqtrade.exchange.cancel_stoploss_order(trade.stoploss_order_id,
|
||||||
trade.pair)
|
trade.pair)
|
||||||
c_count += 1
|
c_count += 1
|
||||||
except (ExchangeError, InvalidOrderException):
|
except (ExchangeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
Trade.session.delete(trade)
|
Trade.session.delete(trade)
|
||||||
|
@ -1301,7 +1301,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
|
|||||||
freqtrade.enter_positions()
|
freqtrade.enter_positions()
|
||||||
trade = Trade.query.first()
|
trade = Trade.query.first()
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
freqtrade.create_stoploss_order(trade, 200, 199)
|
freqtrade.create_stoploss_order(trade, 200)
|
||||||
assert trade.stoploss_order_id is None
|
assert trade.stoploss_order_id is None
|
||||||
assert trade.sell_reason == SellType.EMERGENCY_SELL.value
|
assert trade.sell_reason == SellType.EMERGENCY_SELL.value
|
||||||
assert log_has("Unable to place a stoploss order on exchange. ", caplog)
|
assert log_has("Unable to place a stoploss order on exchange. ", caplog)
|
||||||
@ -4107,7 +4107,7 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order,
|
|||||||
def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order, limit_sell_order):
|
def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order, limit_sell_order):
|
||||||
default_conf['cancel_open_orders_on_exit'] = True
|
default_conf['cancel_open_orders_on_exit'] = True
|
||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
|
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
|
||||||
side_effect=[DependencyException(), limit_sell_order, limit_buy_order])
|
side_effect=[ExchangeError(), limit_sell_order, limit_buy_order])
|
||||||
buy_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_buy')
|
buy_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_buy')
|
||||||
sell_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_sell')
|
sell_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_sell')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user