change how missing candles will be handled

This commit is contained in:
Timothy Pogue 2022-11-25 19:04:51 -07:00
parent 9660e445b8
commit 4cbb3341d7
3 changed files with 15 additions and 37 deletions

View File

@ -7,9 +7,9 @@ Common Interface for bot and strategy to access data.
import logging import logging
from collections import deque from collections import deque
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple, Union
from pandas import DataFrame, concat, date_range from pandas import DataFrame, concat
from freqtrade.configuration import TimeRange from freqtrade.configuration import TimeRange
from freqtrade.constants import Config, ListPairsWithTimeframes, PairWithTimeframe from freqtrade.constants import Config, ListPairsWithTimeframes, PairWithTimeframe
@ -165,40 +165,36 @@ class DataProvider:
timeframe: str, timeframe: str,
candle_type: CandleType, candle_type: CandleType,
producer_name: str = "default" producer_name: str = "default"
) -> Tuple[bool, Optional[List[str]]]: ) -> Union[bool, int]:
""" """
Append a candle to the existing external dataframe Append a candle to the existing external dataframe
:param pair: pair to get the data for :param pair: pair to get the data for
:param timeframe: Timeframe to get data for :param timeframe: Timeframe to get data for
:param candle_type: Any of the enum CandleType (must match trading mode!) :param candle_type: Any of the enum CandleType (must match trading mode!)
:returns: A tuple with a boolean value signifying if the candle was correctly appended, :returns: False if the candle could not be appended, or the int number of missing candles.
and a list of datetimes missing from the candle if it finds some.
Will return false if has no data for `producer_name`.
Will return false if no existing data for (pair, timeframe, candle_type).
Will return false if there's missing candles, and a list of datetimes of
the missing candles.
""" """
pair_key = (pair, timeframe, candle_type) pair_key = (pair, timeframe, candle_type)
if producer_name not in self.__producer_pairs_df: if producer_name not in self.__producer_pairs_df:
# We don't have data from this producer yet, # We don't have data from this producer yet,
# so we can't append a candle # so we can't append a candle
return (False, None) return False
if pair_key not in self.__producer_pairs_df[producer_name]: if pair_key not in self.__producer_pairs_df[producer_name]:
# We don't have data for this pair_key, # We don't have data for this pair_key,
# so we can't append a candle # so we can't append a candle
return (False, None) return False
# CHECK FOR MISSING CANDLES # CHECK FOR MISSING CANDLES
# return int
existing_df, _ = self.__producer_pairs_df[producer_name][pair_key] existing_df, _ = self.__producer_pairs_df[producer_name][pair_key]
appended_df = self._append_candle_to_dataframe(existing_df, dataframe) appended_df = self._append_candle_to_dataframe(existing_df, dataframe)
# Everything is good, we appended # Everything is good, we appended
self.__producer_pairs_df[producer_name][pair_key] = appended_df, last_analyzed self.__producer_pairs_df[producer_name][pair_key] = appended_df, last_analyzed
return (True, None) return True
def _append_candle_to_dataframe(self, existing: DataFrame, new: DataFrame) -> DataFrame: def _append_candle_to_dataframe(self, existing: DataFrame, new: DataFrame) -> DataFrame:
""" """
@ -212,25 +208,10 @@ class DataProvider:
existing = concat([existing, new]) existing = concat([existing, new])
# Only keep the last 1000 candles in memory # Only keep the last 1000 candles in memory
# TODO: Do this better
existing = existing[-1000:] if len(existing) > 1000 else existing existing = existing[-1000:] if len(existing) > 1000 else existing
return existing return existing
def _is_missing_candles(self, dataframe: DataFrame) -> bool:
"""
Check if the dataframe is missing any candles
:param dataframe: The DataFrame to check
"""
logger.info(dataframe.index)
return len(
date_range(
dataframe.index.min(),
dataframe.index.max()
).difference(dataframe.index)
) > 0
def get_producer_df( def get_producer_df(
self, self,
pair: str, pair: str,

View File

@ -388,8 +388,8 @@ class ExternalMessageConsumer:
producer_name=producer_name producer_name=producer_name
) )
elif len(df) == 1: elif len(df) < 999:
# This is just a single candle # This is n single candles
# Have dataprovider append it to # Have dataprovider append it to
# the full datafame. If it can't, # the full datafame. If it can't,
# request the missing candles # request the missing candles

View File

@ -1062,31 +1062,28 @@ class RPC:
self, self,
pair: str, pair: str,
timeframe: str, timeframe: str,
limit: Optional[Union[int, List[str]]] = None limit: Optional[int] = None
) -> Tuple[DataFrame, datetime]: ) -> Tuple[DataFrame, datetime]:
""" """
Get the dataframe and last analyze from the dataprovider Get the dataframe and last analyze from the dataprovider
:param pair: The pair to get :param pair: The pair to get
:param timeframe: The timeframe of data to get :param timeframe: The timeframe of data to get
:param limit: If an integer, limits the size of dataframe :param limit: The amount of candles in the dataframe
If a list of string date times, only returns those candles
""" """
_data, last_analyzed = self._freqtrade.dataprovider.get_analyzed_dataframe( _data, last_analyzed = self._freqtrade.dataprovider.get_analyzed_dataframe(
pair, timeframe) pair, timeframe)
_data = _data.copy() _data = _data.copy()
if limit and isinstance(limit, int): if limit:
_data = _data.iloc[-limit:] _data = _data.iloc[-limit:]
elif limit and isinstance(limit, str):
_data = _data.iloc[_data['date'].isin(limit)]
return _data, last_analyzed return _data, last_analyzed
def _ws_all_analysed_dataframes( def _ws_all_analysed_dataframes(
self, self,
pairlist: List[str], pairlist: List[str],
limit: Optional[Union[int, List[str]]] = None limit: Optional[int] = None
) -> Generator[Dict[str, Any], None, None]: ) -> Generator[Dict[str, Any], None, None]:
""" """
Get the analysed dataframes of each pair in the pairlist. Get the analysed dataframes of each pair in the pairlist.
@ -1113,7 +1110,7 @@ class RPC:
def _ws_request_analyzed_df( def _ws_request_analyzed_df(
self, self,
pair: Optional[str], pair: Optional[str],
limit: Optional[Union[int, List[str]]] = None, limit: Optional[int] = None,
): ):
""" Historical Analyzed Dataframes for WebSocket """ """ Historical Analyzed Dataframes for WebSocket """
pairlist = [pair] if pair else self._freqtrade.active_pair_whitelist pairlist = [pair] if pair else self._freqtrade.active_pair_whitelist