Merge branch 'freqtrade:develop' into strategy_utils

This commit is contained in:
hippocritical 2023-03-12 14:40:02 +01:00 committed by GitHub
commit d186f8f1e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 30 additions and 22 deletions

View File

@ -12,6 +12,9 @@ This page provides you some basic concepts on how Freqtrade works and operates.
* **Indicators**: Technical indicators (SMA, EMA, RSI, ...). * **Indicators**: Technical indicators (SMA, EMA, RSI, ...).
* **Limit order**: Limit orders which execute at the defined limit price or better. * **Limit order**: Limit orders which execute at the defined limit price or better.
* **Market order**: Guaranteed to fill, may move price depending on the order size. * **Market order**: Guaranteed to fill, may move price depending on the order size.
* **Current Profit**: Currently pending (unrealized) profit for this trade. This is mainly used throughout the bot and UI.
* **Realized Profit**: Already realized profit. Only relevant in combination with [partial exits](strategy-callbacks.md#adjust-trade-position) - which also explains the calculation logic for this.
* **Total Profit**: Combined realized and unrealized profit. The relative number (%) is calculated against the total investment in this trade.
## Fee handling ## Fee handling

View File

@ -4,6 +4,7 @@ from enum import Enum
class RPCMessageType(str, Enum): class RPCMessageType(str, Enum):
STATUS = 'status' STATUS = 'status'
WARNING = 'warning' WARNING = 'warning'
EXCEPTION = 'exception'
STARTUP = 'startup' STARTUP = 'startup'
ENTRY = 'entry' ENTRY = 'entry'

View File

@ -133,13 +133,13 @@ class FreqtradeBot(LoggingMixin):
# Initialize protections AFTER bot start - otherwise parameters are not loaded. # Initialize protections AFTER bot start - otherwise parameters are not loaded.
self.protections = ProtectionManager(self.config, self.strategy.protections) self.protections = ProtectionManager(self.config, self.strategy.protections)
def notify_status(self, msg: str) -> None: def notify_status(self, msg: str, msg_type=RPCMessageType.STATUS) -> None:
""" """
Public method for users of this class (worker, etc.) to send notifications Public method for users of this class (worker, etc.) to send notifications
via RPC about changes in the bot status. via RPC about changes in the bot status.
""" """
self.rpc.send_msg({ self.rpc.send_msg({
'type': RPCMessageType.STATUS, 'type': msg_type,
'status': msg 'status': msg
}) })
@ -1460,34 +1460,32 @@ class FreqtradeBot(LoggingMixin):
return False return False
try: try:
co = self.exchange.cancel_order_with_result(order['id'], trade.pair, order = self.exchange.cancel_order_with_result(order['id'], trade.pair,
trade.amount) trade.amount)
except InvalidOrderException: except InvalidOrderException:
logger.exception( logger.exception(
f"Could not cancel {trade.exit_side} order {trade.open_order_id}") f"Could not cancel {trade.exit_side} order {trade.open_order_id}")
return False return False
trade.close_rate = None
trade.close_rate_requested = None
trade.close_profit = None
trade.close_profit_abs = None
# Set exit_reason for fill message # Set exit_reason for fill message
exit_reason_prev = trade.exit_reason exit_reason_prev = trade.exit_reason
trade.exit_reason = trade.exit_reason + f", {reason}" if trade.exit_reason else reason trade.exit_reason = trade.exit_reason + f", {reason}" if trade.exit_reason else reason
self.update_trade_state(trade, trade.open_order_id, co)
# Order might be filled above in odd timing issues. # Order might be filled above in odd timing issues.
if co.get('status') in ('canceled', 'cancelled'): if order.get('status') in ('canceled', 'cancelled'):
trade.exit_reason = None trade.exit_reason = None
trade.open_order_id = None
else: else:
trade.exit_reason = exit_reason_prev trade.exit_reason = exit_reason_prev
logger.info(f'{trade.exit_side.capitalize()} order {reason} for {trade}.')
cancelled = True cancelled = True
else: else:
reason = constants.CANCEL_REASON['CANCELLED_ON_EXCHANGE'] reason = constants.CANCEL_REASON['CANCELLED_ON_EXCHANGE']
logger.info(f'{trade.exit_side.capitalize()} order {reason} for {trade}.') trade.exit_reason = None
self.update_trade_state(trade, trade.open_order_id, order) self.update_trade_state(trade, trade.open_order_id, order)
logger.info(f'{trade.exit_side.capitalize()} order {reason} for {trade}.')
trade.open_order_id = None trade.open_order_id = None
trade.close_rate = None
trade.close_rate_requested = None
self._notify_exit_cancel( self._notify_exit_cancel(
trade, trade,

View File

@ -6,8 +6,7 @@ import logging
import re import re
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Iterator, List, Mapping, Optional, Union from typing import Any, Dict, Iterator, List, Mapping, Optional, TextIO, Union
from typing.io import IO
from urllib.parse import urlparse from urllib.parse import urlparse
import orjson import orjson
@ -103,7 +102,7 @@ def file_dump_joblib(filename: Path, data: Any, log: bool = True) -> None:
logger.debug(f'done joblib dump to "{filename}"') logger.debug(f'done joblib dump to "{filename}"')
def json_load(datafile: IO) -> Any: def json_load(datafile: Union[gzip.GzipFile, TextIO]) -> Any:
""" """
load data with rapidjson load data with rapidjson
Use this to have a consistent experience, Use this to have a consistent experience,

View File

@ -414,6 +414,9 @@ class Telegram(RPCHandler):
elif msg_type == RPCMessageType.WARNING: elif msg_type == RPCMessageType.WARNING:
message = f"\N{WARNING SIGN} *Warning:* `{msg['status']}`" message = f"\N{WARNING SIGN} *Warning:* `{msg['status']}`"
elif msg_type == RPCMessageType.EXCEPTION:
# Errors will contain exceptions, which are wrapped in tripple ticks.
message = f"\N{WARNING SIGN} *ERROR:* \n {msg['status']}"
elif msg_type == RPCMessageType.STARTUP: elif msg_type == RPCMessageType.STARTUP:
message = f"{msg['status']}" message = f"{msg['status']}"

View File

@ -58,6 +58,7 @@ class Webhook(RPCHandler):
valuedict = whconfig.get('webhookexitcancel') valuedict = whconfig.get('webhookexitcancel')
elif msg['type'] in (RPCMessageType.STATUS, elif msg['type'] in (RPCMessageType.STATUS,
RPCMessageType.STARTUP, RPCMessageType.STARTUP,
RPCMessageType.EXCEPTION,
RPCMessageType.WARNING): RPCMessageType.WARNING):
valuedict = whconfig.get('webhookstatus') valuedict = whconfig.get('webhookstatus')
elif msg['type'].value in whconfig: elif msg['type'].value in whconfig:

View File

@ -12,7 +12,7 @@ import sdnotify
from freqtrade import __version__ from freqtrade import __version__
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration
from freqtrade.constants import PROCESS_THROTTLE_SECS, RETRY_TIMEOUT, Config from freqtrade.constants import PROCESS_THROTTLE_SECS, RETRY_TIMEOUT, Config
from freqtrade.enums import State from freqtrade.enums import RPCMessageType, State
from freqtrade.exceptions import OperationalException, TemporaryError from freqtrade.exceptions import OperationalException, TemporaryError
from freqtrade.exchange import timeframe_to_next_date from freqtrade.exchange import timeframe_to_next_date
from freqtrade.freqtradebot import FreqtradeBot from freqtrade.freqtradebot import FreqtradeBot
@ -185,7 +185,10 @@ class Worker:
tb = traceback.format_exc() tb = traceback.format_exc()
hint = 'Issue `/start` if you think it is safe to restart.' hint = 'Issue `/start` if you think it is safe to restart.'
self.freqtrade.notify_status(f'OperationalException:\n```\n{tb}```{hint}') self.freqtrade.notify_status(
f'*OperationalException:*\n```\n{tb}```\n {hint}',
msg_type=RPCMessageType.EXCEPTION
)
logger.exception('OperationalException. Stopping trader ...') logger.exception('OperationalException. Stopping trader ...')
self.freqtrade.state = State.STOPPED self.freqtrade.state = State.STOPPED

View File

@ -2,7 +2,7 @@ numpy==1.24.2
pandas==1.5.3 pandas==1.5.3
pandas-ta==0.3.14b pandas-ta==0.3.14b
ccxt==2.9.4 ccxt==2.9.12
cryptography==39.0.2 cryptography==39.0.2
aiohttp==3.8.4 aiohttp==3.8.4
SQLAlchemy==2.0.5.post1 SQLAlchemy==2.0.5.post1