change how missing candles will be handled
This commit is contained in:
parent
9660e445b8
commit
4cbb3341d7
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user