Update more to use candleType
This commit is contained in:
parent
5493212672
commit
2f17fa2765
@ -11,7 +11,7 @@ import pandas as pd
|
||||
from pandas import DataFrame, to_datetime
|
||||
|
||||
from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, DEFAULT_TRADES_COLUMNS, TradeList
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums import CandleType
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -13,8 +13,7 @@ from pandas import DataFrame
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.constants import ListPairsWithTimeframes, PairWithTimeframe
|
||||
from freqtrade.data.history import load_pair_history
|
||||
from freqtrade.enums import RunMode
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums import CandleType, RunMode
|
||||
from freqtrade.exceptions import ExchangeError, OperationalException
|
||||
from freqtrade.exchange import Exchange, timeframe_to_seconds
|
||||
|
||||
@ -223,7 +222,7 @@ class DataProvider:
|
||||
raise OperationalException(NO_EXCHANGE_EXCEPTION)
|
||||
if self.runmode in (RunMode.DRY_RUN, RunMode.LIVE):
|
||||
return self._exchange.klines(
|
||||
(pair, timeframe or self._config['timeframe'], candle_type),
|
||||
(pair, timeframe or self._config['timeframe'], CandleType.from_string(candle_type)),
|
||||
copy=copy
|
||||
)
|
||||
else:
|
||||
|
@ -9,7 +9,7 @@ import pandas as pd
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.constants import (DEFAULT_DATAFRAME_COLUMNS, DEFAULT_TRADES_COLUMNS,
|
||||
ListPairsWithTimeframes, TradeList)
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums import CandleType
|
||||
|
||||
from .idatahandler import IDataHandler
|
||||
|
||||
|
@ -12,7 +12,7 @@ from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS
|
||||
from freqtrade.data.converter import (clean_ohlcv_dataframe, ohlcv_to_dataframe,
|
||||
trades_remove_duplicates, trades_to_ohlcv)
|
||||
from freqtrade.data.history.idatahandler import IDataHandler, get_datahandler
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exchange import Exchange
|
||||
from freqtrade.misc import format_ms_time
|
||||
|
@ -17,7 +17,7 @@ from freqtrade import misc
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.constants import ListPairsWithTimeframes, TradeList
|
||||
from freqtrade.data.converter import clean_ohlcv_dataframe, trades_remove_duplicates, trim_dataframe
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exchange import timeframe_to_seconds
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@ from freqtrade import misc
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, ListPairsWithTimeframes, TradeList
|
||||
from freqtrade.data.converter import trades_dict_to_list
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums import CandleType
|
||||
|
||||
from .idatahandler import IDataHandler
|
||||
|
||||
|
@ -8,7 +8,7 @@ from typing import Dict, List, Optional, Tuple
|
||||
import arrow
|
||||
import ccxt
|
||||
|
||||
from freqtrade.enums import Collateral, TradingMode
|
||||
from freqtrade.enums import CandleType, Collateral, TradingMode
|
||||
from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException,
|
||||
OperationalException, TemporaryError)
|
||||
from freqtrade.exchange import Exchange
|
||||
@ -197,14 +197,13 @@ class Binance(Exchange):
|
||||
raise OperationalException(e) from e
|
||||
|
||||
async def _async_get_historic_ohlcv(self, pair: str, timeframe: str,
|
||||
since_ms: int, is_new_pair: bool = False,
|
||||
raise_: bool = False,
|
||||
candle_type: str = ''
|
||||
since_ms: int, candle_type: CandleType,
|
||||
is_new_pair: bool = False, raise_: bool = False,
|
||||
) -> Tuple[str, str, str, List]:
|
||||
"""
|
||||
Overwrite to introduce "fast new pair" functionality by detecting the pair's listing date
|
||||
Does not work for other exchanges, which don't return the earliest data when called with "0"
|
||||
:param candle_type: '', mark, index, premiumIndex, or funding_rate
|
||||
:param candle_type: Any of the enum CandleType (must match trading mode!)
|
||||
"""
|
||||
if is_new_pair:
|
||||
x = await self._async_get_candle_history(pair, timeframe, 0, candle_type)
|
||||
|
@ -20,9 +20,9 @@ from ccxt.base.decimal_to_precision import (ROUND_DOWN, ROUND_UP, TICK_SIZE, TRU
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES,
|
||||
ListPairsWithTimeframes)
|
||||
ListPairsWithTimeframes, PairWithTimeframe)
|
||||
from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list
|
||||
from freqtrade.enums import Collateral, TradingMode
|
||||
from freqtrade.enums import CandleType, Collateral, TradingMode
|
||||
from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFundsError,
|
||||
InvalidOrderException, OperationalException, PricingError,
|
||||
RetryableOrderError, TemporaryError)
|
||||
@ -92,7 +92,7 @@ class Exchange:
|
||||
self._config.update(config)
|
||||
|
||||
# Holds last candle refreshed time of each pair
|
||||
self._pairs_last_refresh_time: Dict[Tuple[str, str, str], int] = {}
|
||||
self._pairs_last_refresh_time: Dict[PairWithTimeframe, int] = {}
|
||||
# Timestamp of last markets refresh
|
||||
self._last_markets_refresh: int = 0
|
||||
|
||||
@ -105,7 +105,7 @@ class Exchange:
|
||||
self._buy_rate_cache: TTLCache = TTLCache(maxsize=100, ttl=1800)
|
||||
|
||||
# Holds candles
|
||||
self._klines: Dict[Tuple[str, str, str], DataFrame] = {}
|
||||
self._klines: Dict[PairWithTimeframe, DataFrame] = {}
|
||||
|
||||
# Holds all open sell orders for dry_run
|
||||
self._dry_run_open_orders: Dict[str, Any] = {}
|
||||
@ -359,7 +359,7 @@ class Exchange:
|
||||
or (self.trading_mode == TradingMode.FUTURES and self.market_is_future(market))
|
||||
)
|
||||
|
||||
def klines(self, pair_interval: Tuple[str, str, str], copy: bool = True) -> DataFrame:
|
||||
def klines(self, pair_interval: PairWithTimeframe, copy: bool = True) -> DataFrame:
|
||||
if pair_interval in self._klines:
|
||||
return self._klines[pair_interval].copy() if copy else self._klines[pair_interval]
|
||||
else:
|
||||
@ -1314,8 +1314,8 @@ class Exchange:
|
||||
# Historic data
|
||||
|
||||
def get_historic_ohlcv(self, pair: str, timeframe: str,
|
||||
since_ms: int, is_new_pair: bool = False,
|
||||
candle_type: str = '') -> List:
|
||||
since_ms: int, candle_type: CandleType,
|
||||
is_new_pair: bool = False) -> List:
|
||||
"""
|
||||
Get candle history using asyncio and returns the list of candles.
|
||||
Handles all async work for this.
|
||||
@ -1327,7 +1327,7 @@ class Exchange:
|
||||
:return: List with candle (OHLCV) data
|
||||
"""
|
||||
data: List
|
||||
pair, timeframe, candle_type, data = asyncio.get_event_loop().run_until_complete(
|
||||
pair, _, _, data = asyncio.get_event_loop().run_until_complete(
|
||||
self._async_get_historic_ohlcv(pair=pair, timeframe=timeframe,
|
||||
since_ms=since_ms, is_new_pair=is_new_pair,
|
||||
candle_type=candle_type))
|
||||
@ -1335,13 +1335,13 @@ class Exchange:
|
||||
return data
|
||||
|
||||
def get_historic_ohlcv_as_df(self, pair: str, timeframe: str,
|
||||
since_ms: int, candle_type: str = '') -> DataFrame:
|
||||
since_ms: int, candle_type: CandleType) -> DataFrame:
|
||||
"""
|
||||
Minimal wrapper around get_historic_ohlcv - converting the result into a dataframe
|
||||
:param pair: Pair to download
|
||||
:param timeframe: Timeframe to get data for
|
||||
:param since_ms: Timestamp in milliseconds to get history from
|
||||
:param candle_type: '', mark, index, premiumIndex, or funding_rate
|
||||
:param candle_type: Any of the enum CandleType (must match trading mode!)
|
||||
:return: OHLCV DataFrame
|
||||
"""
|
||||
ticks = self.get_historic_ohlcv(pair, timeframe, since_ms=since_ms, candle_type=candle_type)
|
||||
@ -1349,14 +1349,13 @@ class Exchange:
|
||||
drop_incomplete=self._ohlcv_partial_candle)
|
||||
|
||||
async def _async_get_historic_ohlcv(self, pair: str, timeframe: str,
|
||||
since_ms: int, is_new_pair: bool = False,
|
||||
raise_: bool = False,
|
||||
candle_type: str = ''
|
||||
since_ms: int, candle_type: CandleType,
|
||||
is_new_pair: bool = False, raise_: bool = False,
|
||||
) -> Tuple[str, str, str, List]:
|
||||
"""
|
||||
Download historic ohlcv
|
||||
:param is_new_pair: used by binance subclass to allow "fast" new pair downloading
|
||||
:param candle_type: '', mark, index, premiumIndex, or funding_rate
|
||||
:param candle_type: Any of the enum CandleType (must match trading mode!)
|
||||
"""
|
||||
|
||||
one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe)
|
||||
@ -1391,8 +1390,8 @@ class Exchange:
|
||||
|
||||
def refresh_latest_ohlcv(self, pair_list: ListPairsWithTimeframes, *,
|
||||
since_ms: Optional[int] = None, cache: bool = True,
|
||||
candle_type: str = ''
|
||||
) -> Dict[Tuple[str, str, str], DataFrame]:
|
||||
candle_type: CandleType = CandleType.SPOT_
|
||||
) -> Dict[PairWithTimeframe, DataFrame]:
|
||||
"""
|
||||
Refresh in-memory OHLCV asynchronously and set `_klines` with the result
|
||||
Loops asynchronously over pair_list and downloads all pairs async (semi-parallel).
|
||||
@ -1410,7 +1409,7 @@ class Exchange:
|
||||
# Gather coroutines to run
|
||||
for pair, timeframe, candle_type in set(pair_list):
|
||||
if ((pair, timeframe, candle_type) not in self._klines or not cache
|
||||
or self._now_is_time_to_refresh(pair, timeframe)):
|
||||
or self._now_is_time_to_refresh(pair, timeframe, candle_type)):
|
||||
if not since_ms and self.required_candle_call_count > 1:
|
||||
# Multiple calls for one pair - to get more history
|
||||
one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe)
|
||||
@ -1463,12 +1462,7 @@ class Exchange:
|
||||
|
||||
return results_df
|
||||
|
||||
def _now_is_time_to_refresh(
|
||||
self,
|
||||
pair: str,
|
||||
timeframe: str,
|
||||
candle_type: str = ''
|
||||
) -> bool:
|
||||
def _now_is_time_to_refresh(self, pair: str, timeframe: str, candle_type: CandleType) -> bool:
|
||||
# Timeframe in seconds
|
||||
interval_in_sec = timeframe_to_seconds(timeframe)
|
||||
|
||||
|
@ -17,9 +17,7 @@ from freqtrade.data import history
|
||||
from freqtrade.data.btanalysis import trade_list_to_dataframe
|
||||
from freqtrade.data.converter import trim_dataframe, trim_dataframes
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import BacktestState, SellType
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums.tradingmode import TradingMode
|
||||
from freqtrade.enums import BacktestState, CandleType, SellType, TradingMode
|
||||
from freqtrade.exceptions import DependencyException, OperationalException
|
||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||
from freqtrade.mixins import LoggingMixin
|
||||
|
@ -9,6 +9,7 @@ import arrow
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.configuration import PeriodicCache
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.misc import plural
|
||||
from freqtrade.plugins.pairlist.IPairList import IPairList
|
||||
@ -72,7 +73,7 @@ class AgeFilter(IPairList):
|
||||
:return: new allowlist
|
||||
"""
|
||||
needed_pairs = [
|
||||
(p, '1d', '') for p in pairlist
|
||||
(p, '1d', CandleType.SPOT_) for p in pairlist
|
||||
if p not in self._symbolsChecked and p not in self._symbolsCheckFailed]
|
||||
if not needed_pairs:
|
||||
# Remove pairs that have been removed before
|
||||
@ -88,7 +89,8 @@ class AgeFilter(IPairList):
|
||||
candles = self._exchange.refresh_latest_ohlcv(needed_pairs, since_ms=since_ms, cache=False)
|
||||
if self._enabled:
|
||||
for p in deepcopy(pairlist):
|
||||
daily_candles = candles[(p, '1d', '')] if (p, '1d', '') in candles else None
|
||||
daily_candles = candles[(p, '1d', CandleType.SPOT_)] if (
|
||||
p, '1d', CandleType.SPOT_) in candles else None
|
||||
if not self._validate_pair_loc(p, daily_candles):
|
||||
pairlist.remove(p)
|
||||
self.log_once(f"Validated {len(pairlist)} pairs.", logger.info)
|
||||
|
@ -5,7 +5,7 @@ import logging
|
||||
import random
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from freqtrade.enums.runmode import RunMode
|
||||
from freqtrade.enums import RunMode
|
||||
from freqtrade.plugins.pairlist.IPairList import IPairList
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@ import numpy as np
|
||||
from cachetools.ttl import TTLCache
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.misc import plural
|
||||
from freqtrade.plugins.pairlist.IPairList import IPairList
|
||||
@ -67,7 +68,7 @@ class VolatilityFilter(IPairList):
|
||||
:param tickers: Tickers (from exchange.get_tickers()). May be cached.
|
||||
:return: new allowlist
|
||||
"""
|
||||
needed_pairs = [(p, '1d', '') for p in pairlist if p not in self._pair_cache]
|
||||
needed_pairs = [(p, '1d', CandleType.SPOT_) for p in pairlist if p not in self._pair_cache]
|
||||
|
||||
since_ms = (arrow.utcnow()
|
||||
.floor('day')
|
||||
@ -81,7 +82,8 @@ class VolatilityFilter(IPairList):
|
||||
|
||||
if self._enabled:
|
||||
for p in deepcopy(pairlist):
|
||||
daily_candles = candles[(p, '1d', '')] if (p, '1d', '') in candles else None
|
||||
daily_candles = candles[(p, '1d', CandleType.SPOT_)] if (
|
||||
p, '1d', CandleType.SPOT_) in candles else None
|
||||
if not self._validate_pair_loc(p, daily_candles):
|
||||
pairlist.remove(p)
|
||||
return pairlist
|
||||
|
@ -10,6 +10,7 @@ from typing import Any, Dict, List
|
||||
import arrow
|
||||
from cachetools.ttl import TTLCache
|
||||
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from freqtrade.misc import format_ms_time
|
||||
@ -160,7 +161,7 @@ class VolumePairList(IPairList):
|
||||
f"{self._lookback_timeframe}, starting from {format_ms_time(since_ms)} "
|
||||
f"till {format_ms_time(to_ms)}", logger.info)
|
||||
needed_pairs = [
|
||||
(p, self._lookback_timeframe, '') for p in
|
||||
(p, self._lookback_timeframe, CandleType.SPOT_) for p in
|
||||
[s['symbol'] for s in filtered_tickers]
|
||||
if p not in self._pair_cache
|
||||
]
|
||||
@ -173,8 +174,8 @@ class VolumePairList(IPairList):
|
||||
)
|
||||
for i, p in enumerate(filtered_tickers):
|
||||
pair_candles = candles[
|
||||
(p['symbol'], self._lookback_timeframe, '')
|
||||
] if (p['symbol'], self._lookback_timeframe, '') in candles else None
|
||||
(p['symbol'], self._lookback_timeframe, CandleType.SPOT_)
|
||||
] if (p['symbol'], self._lookback_timeframe, CandleType.SPOT_) in candles else None
|
||||
# in case of candle data calculate typical price and quoteVolume for candle
|
||||
if pair_candles is not None and not pair_candles.empty:
|
||||
pair_candles['typical_price'] = (pair_candles['high'] + pair_candles['low']
|
||||
|
@ -9,6 +9,7 @@ import arrow
|
||||
from cachetools.ttl import TTLCache
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.misc import plural
|
||||
from freqtrade.plugins.pairlist.IPairList import IPairList
|
||||
@ -65,7 +66,7 @@ class RangeStabilityFilter(IPairList):
|
||||
:param tickers: Tickers (from exchange.get_tickers()). May be cached.
|
||||
:return: new allowlist
|
||||
"""
|
||||
needed_pairs = [(p, '1d', '') for p in pairlist if p not in self._pair_cache]
|
||||
needed_pairs = [(p, '1d', CandleType.SPOT_) for p in pairlist if p not in self._pair_cache]
|
||||
|
||||
since_ms = (arrow.utcnow()
|
||||
.floor('day')
|
||||
@ -79,7 +80,8 @@ class RangeStabilityFilter(IPairList):
|
||||
|
||||
if self._enabled:
|
||||
for p in deepcopy(pairlist):
|
||||
daily_candles = candles[(p, '1d', '')] if (p, '1d', '') in candles else None
|
||||
daily_candles = candles[(p, '1d', CandleType.SPOT_)] if (
|
||||
p, '1d', CandleType.SPOT_) in candles else None
|
||||
if not self._validate_pair_loc(p, daily_candles):
|
||||
pairlist.remove(p)
|
||||
return pairlist
|
||||
|
@ -8,6 +8,7 @@ from typing import Dict, List
|
||||
from cachetools import TTLCache, cached
|
||||
|
||||
from freqtrade.constants import ListPairsWithTimeframes
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.plugins.pairlist.IPairList import IPairList
|
||||
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
|
||||
@ -138,4 +139,4 @@ class PairListManager():
|
||||
"""
|
||||
Create list of pair tuples with (pair, timeframe)
|
||||
"""
|
||||
return [(pair, timeframe or self._config['timeframe'], '') for pair in pairs]
|
||||
return [(pair, timeframe or self._config['timeframe'], CandleType.SPOT) for pair in pairs]
|
||||
|
@ -9,6 +9,7 @@ from fastapi.exceptions import HTTPException
|
||||
from freqtrade import __version__
|
||||
from freqtrade.constants import USERPATH_STRATEGIES
|
||||
from freqtrade.data.history import get_datahandler
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.rpc import RPC
|
||||
from freqtrade.rpc.api_server.api_schemas import (AvailablePairs, Balances, BlacklistPayload,
|
||||
@ -250,7 +251,7 @@ def get_strategy(strategy: str, config=Depends(get_config)):
|
||||
|
||||
@router.get('/available_pairs', response_model=AvailablePairs, tags=['candle data'])
|
||||
def list_available_pairs(timeframe: Optional[str] = None, stake_currency: Optional[str] = None,
|
||||
candletype: Optional[str] = None, config=Depends(get_config)):
|
||||
candletype: Optional[CandleType] = None, config=Depends(get_config)):
|
||||
|
||||
dh = get_datahandler(config['datadir'], config.get('dataformat_ohlcv', None))
|
||||
|
||||
|
@ -2,6 +2,7 @@ from typing import Any, Callable, NamedTuple, Optional, Union
|
||||
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.enums import CandleType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.strategy.strategy_helper import merge_informative_pair
|
||||
|
||||
@ -14,7 +15,7 @@ class InformativeData(NamedTuple):
|
||||
timeframe: str
|
||||
fmt: Union[str, Callable[[Any], str], None]
|
||||
ffill: bool
|
||||
candle_type: str = ''
|
||||
candle_type: CandleType = CandleType.SPOT_
|
||||
|
||||
|
||||
def informative(timeframe: str, asset: str = '',
|
||||
|
@ -13,8 +13,7 @@ from pandas import DataFrame
|
||||
|
||||
from freqtrade.constants import ListPairsWithTimeframes
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import SellType, SignalDirection, SignalTagType, SignalType
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums import CandleType, SellType, SignalDirection, SignalTagType, SignalType
|
||||
from freqtrade.exceptions import OperationalException, StrategyError
|
||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||
from freqtrade.exchange.exchange import timeframe_to_next_date
|
||||
@ -424,7 +423,9 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
"""
|
||||
informative_pairs = self.informative_pairs()
|
||||
# Compatibility code for 2 tuple informative pairs
|
||||
informative_pairs = [(p[0], p[1], p[2] if len(p) > 2 else '') for p in informative_pairs]
|
||||
informative_pairs = [
|
||||
(p[0], p[1], CandleType.from_string(p[2]) if len(p) > 2 else CandleType.SPOT_)
|
||||
for p in informative_pairs]
|
||||
for inf_data, _ in self._ft_informative:
|
||||
if inf_data.asset:
|
||||
pair_tf = (
|
||||
|
Loading…
Reference in New Issue
Block a user