Merge pull request #7862 from freqtrade/ws_newcandle

New websocket message "new_candle"
This commit is contained in:
Matthias 2022-12-06 07:07:32 +01:00 committed by GitHub
commit e7195b7bfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 32 additions and 13 deletions

View File

@ -104,13 +104,15 @@ class DataProvider:
def _emit_df(
self,
pair_key: PairWithTimeframe,
dataframe: DataFrame
dataframe: DataFrame,
new_candle: bool
) -> None:
"""
Send this dataframe as an ANALYZED_DF message to RPC
:param pair_key: PairWithTimeframe tuple
:param data: Tuple containing the DataFrame and the datetime it was cached
:param dataframe: Dataframe to emit
:param new_candle: This is a new candle
"""
if self.__rpc:
self.__rpc.send_msg(
@ -123,6 +125,11 @@ class DataProvider:
}
}
)
if new_candle:
self.__rpc.send_msg({
'type': RPCMessageType.NEW_CANDLE,
'data': pair_key,
})
def _add_external_df(
self,

View File

@ -6,7 +6,7 @@ from freqtrade.enums.exittype import ExitType
from freqtrade.enums.hyperoptstate import HyperoptState
from freqtrade.enums.marginmode import MarginMode
from freqtrade.enums.ordertypevalue import OrderTypeValues
from freqtrade.enums.rpcmessagetype import RPCMessageType, RPCRequestType
from freqtrade.enums.rpcmessagetype import NO_ECHO_MESSAGES, RPCMessageType, RPCRequestType
from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode
from freqtrade.enums.signaltype import SignalDirection, SignalTagType, SignalType
from freqtrade.enums.state import State

View File

@ -21,6 +21,7 @@ class RPCMessageType(str, Enum):
WHITELIST = 'whitelist'
ANALYZED_DF = 'analyzed_df'
NEW_CANDLE = 'new_candle'
def __repr__(self):
return self.value
@ -35,3 +36,6 @@ class RPCRequestType(str, Enum):
WHITELIST = 'whitelist'
ANALYZED_DF = 'analyzed_df'
NO_ECHO_MESSAGES = (RPCMessageType.ANALYZED_DF, RPCMessageType.WHITELIST, RPCMessageType.NEW_CANDLE)

View File

@ -37,7 +37,8 @@ logger = logging.getLogger(__name__)
# 2.16: Additional daily metrics
# 2.17: Forceentry - leverage, partial force_exit
# 2.20: Add websocket endpoints
API_VERSION = 2.20
# 2.21: Add new_candle messagetype
API_VERSION = 2.21
# Public API, requires no auth.
router_public = APIRouter()

View File

@ -6,7 +6,7 @@ from collections import deque
from typing import Any, Dict, List
from freqtrade.constants import Config
from freqtrade.enums import RPCMessageType
from freqtrade.enums import NO_ECHO_MESSAGES, RPCMessageType
from freqtrade.rpc import RPC, RPCHandler
@ -67,7 +67,7 @@ class RPCManager:
'status': 'stopping bot'
}
"""
if msg.get('type') not in (RPCMessageType.ANALYZED_DF, RPCMessageType.WHITELIST):
if msg.get('type') not in NO_ECHO_MESSAGES:
logger.info('Sending rpc message: %s', msg)
if 'pair' in msg:
msg.update({

View File

@ -68,6 +68,7 @@ class Webhook(RPCHandler):
RPCMessageType.PROTECTION_TRIGGER_GLOBAL,
RPCMessageType.WHITELIST,
RPCMessageType.ANALYZED_DF,
RPCMessageType.NEW_CANDLE,
RPCMessageType.STRATEGY_MSG):
# Don't fail for non-implemented types
return None

View File

@ -739,10 +739,10 @@ class IStrategy(ABC, HyperStrategyMixin):
"""
pair = str(metadata.get('pair'))
new_candle = self._last_candle_seen_per_pair.get(pair, None) != dataframe.iloc[-1]['date']
# Test if seen this pair and last candle before.
# always run if process_only_new_candles is set to false
if (not self.process_only_new_candles or
self._last_candle_seen_per_pair.get(pair, None) != dataframe.iloc[-1]['date']):
if not self.process_only_new_candles or new_candle:
# Defs that only make change on new candle data.
dataframe = self.analyze_ticker(dataframe, metadata)
@ -751,7 +751,7 @@ class IStrategy(ABC, HyperStrategyMixin):
candle_type = self.config.get('candle_type_def', CandleType.SPOT)
self.dp._set_cached_df(pair, self.timeframe, dataframe, candle_type=candle_type)
self.dp._emit_df((pair, self.timeframe, candle_type), dataframe)
self.dp._emit_df((pair, self.timeframe, candle_type), dataframe, new_candle)
else:
logger.debug("Skipping TA Analysis for already analyzed candle")

View File

@ -207,12 +207,18 @@ def test_emit_df(mocker, default_conf, ohlcv_history):
assert send_mock.call_count == 0
# Rpc is added, we call emit, should call send_msg
dataprovider._emit_df(pair, ohlcv_history)
dataprovider._emit_df(pair, ohlcv_history, False)
assert send_mock.call_count == 1
send_mock.reset_mock()
dataprovider._emit_df(pair, ohlcv_history, True)
assert send_mock.call_count == 2
send_mock.reset_mock()
# No rpc added, emit called, should not call send_msg
dataprovider_no_rpc._emit_df(pair, ohlcv_history)
assert send_mock.call_count == 1
dataprovider_no_rpc._emit_df(pair, ohlcv_history, False)
assert send_mock.call_count == 0
def test_refresh(mocker, default_conf, ohlcv_history):

View File

@ -588,7 +588,7 @@ def test_api_show_config(botclient):
assert 'unfilledtimeout' in response
assert 'version' in response
assert 'api_version' in response
assert 2.1 <= response['api_version'] <= 2.2
assert 2.1 <= response['api_version'] < 3.0
def test_api_daily(botclient, mocker, ticker, fee, markets):