freqtrade-自定义动态选币策略-2

动态选币策略

import logging  # noqa: I001
import numpy as np

from freqtrade.exceptions import OperationalException
from freqtrade.exchange.exchange_types import Tickers
from freqtrade.plugins.pairlist.IPairList import IPairList, PairlistParameter, SupportsBacktesting
from cachetools import TTLCache

logger = logging.getLogger(__name__)

class AlphaCoinSelectorPairList(IPairList):
    is_pairlist_generator = True
    supports_backtesting = SupportsBacktesting.YES

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

        if "number_assets" not in self._pairlistconfig:
            raise OperationalException(
                "`number_assets` not specified. Please check your configuration "
                'for "pairlist.config.number_assets"'
            )

        self._stake_currency = self._config["stake_currency"]
        self._number_assets = self._pairlistconfig["number_assets"]
        self._max_rank = self._pairlistconfig.get("max_rank", 30)
        self._refresh_period = self._pairlistconfig.get("refresh_period", 86400)
        self._categories = self._pairlistconfig.get("categories", [])
        self._pair_cache: TTLCache = TTLCache(maxsize=1, ttl=self._refresh_period)

        if self._max_rank > 250:
            self.logger.warning(
                f"The max rank you have set ({self._max_rank}) is quite high. "
                "This may lead to coingecko API rate limit issues. "
                "Please ensure this value is necessary for your use case.",
            )

    @property
    def needstickers(self) -> bool:
        return False

    def short_desc(self) -> str:
        num = self._number_assets
        rank = self._max_rank
        msg = f"{self.name} - {num} pairs selected based on liquidity and volatility."
        return msg

    @staticmethod
    def description() -> str:
        return "Provides pair list based on liquidity and volatility."

    @staticmethod
    def available_parameters() -> dict[str, PairlistParameter]:
        return {
            "number_assets": {
                "type": "number",
                "default": 30,
                "description": "Number of assets",
                "help": "Number of assets to use from the pairlist",
            },
            "max_rank": {
                "type": "number",
                "default": 30,
                "description": "Max rank of assets",
                "help": "Maximum rank of assets to use from the pairlist",
            },
            "refresh_period": {
                "type": "number",
                "default": 86400,
                "description": "Refresh period",
                "help": "Refresh period in seconds",
            },
            "categories": {
                "type": "list",
                "default": [],
                "description": "Coin Categories",
                "help": "The Category of the coin e.g layer-1 default []",
            },
        }

    def gen_pairlist(self, tickers: Tickers) -> list[str]:
        pairlist = self._pair_cache.get("alpha_pairlist")
        if pairlist:
            return pairlist.copy()
        else:
            _pairlist = [
                k
                for k in self._exchange.get_markets(
                    quote_currencies=[self._stake_currency], tradable_only=True, active_only=True
                ).keys()
            ]

            logger.info(f"_pairlist: {str(_pairlist)}")
            _pairlist = self.verify_blacklist(_pairlist, logger.info)
            pairlist = self.filter_pairlist(_pairlist, tickers)
            self._pair_cache["pairlist"] = pairlist.copy()

        return pairlist

    def filter_pairlist(self, pairlist: list[str], tickers: Tickers) -> list[str]:
        selected = []
        for symbol in pairlist:
            market = self._exchange.get_markets().get(symbol)

            logger.info(f"market: {str(market)}")
            if market and self.filter_coin(symbol, market):
                selected.append(symbol)

        return sorted(selected, key=lambda x: self.calc_alpha_score(x), reverse=True)[:self._number_assets]

    def filter_coin(self, symbol, market):
        logger.debug(f"Checking symbol: {symbol}")
        if market['quote'] != 'USDT':
            logger.debug(f"{symbol} excluded: quote is not USDT")
            return False
        if market['type'] != 'spot':
            logger.debug(f"{symbol} excluded: type is not spot")
            return False
        if market['volume24h'] < 2000000:
            logger.debug(f"{symbol} excluded: 24h volume < 2000000")
            return False

        alpha_score = self.calc_alpha_score(symbol, market)
        if alpha_score <= 0.7:
            logger.debug(f"{symbol} excluded: alpha_score <= 0.7")
            return False

        return True

    def calc_alpha_score(self, symbol, market=None):
        if not market:
            market = self._exchange.get_markets().get(symbol)
        if not market:
            return 0

        volatility = self.calc_volatility(symbol)
        liquidity = market['volume24h'] / market['marketCap']
        return volatility * liquidity

    def calc_volatility(self, symbol):
        try:
            ohlcv = self._exchange.get_ohlcv(symbol, '4h', limit=42)
            returns = np.log(ohlcv['close'] / ohlcv['close'].shift(1))
            return returns.std() * np.sqrt(365 * 24 / 4)
        except Exception as e:
            logger.error(f"Failed to calculate volatility for {symbol}: {e}")
            return 0

调试:

(.venv) (base) ➜  freqtrade git:(develop) ✗ freqtrade test-pairlist --config user_data/config/my_config.json
2025-04-25 08:34:39,113 - freqtrade - INFO - main: parsed_args: {'version_main': False, 'command': 'test-pairlist', 'user_data_dir': None, 'verbosity': None, 'config': 
['user_data/config/my_config.json'], 'quote_currencies': None, 'print_one_column': False, 'list_pairs_print_json': False, 'exchange': None, 'func': <function 
start_test_pairlist at 0x108764ae0>}
2025-04-25 08:34:39,114 - freqtrade - INFO - freqtrade 2025.4-dev-82cd343fc
2025-04-25 08:34:39,895 - numexpr.utils - INFO - NumExpr defaulting to 12 threads.
2025-04-25 08:34:43,213 - freqtrade.configuration.load_config - INFO - Using config: user_data/config/my_config.json ...
2025-04-25 08:34:43,221 - freqtrade.loggers - INFO - Enabling colorized output.
2025-04-25 08:34:43,221 - root - INFO - Logfile configured
2025-04-25 08:34:43,222 - freqtrade.loggers - INFO - Verbosity set to 0
2025-04-25 08:34:43,223 - freqtrade.configuration.configuration - INFO - Using user-data directory: /Users/kaiyi/Work/develop/Code/freqtrade/user_data ...
2025-04-25 08:34:43,223 - freqtrade.configuration.configuration - INFO - Using data directory: /Users/kaiyi/Work/develop/Code/freqtrade/user_data/data/binance ...
2025-04-25 08:34:43,225 - freqtrade.exchange.check_exchange - INFO - Checking exchange...
2025-04-25 08:34:43,238 - freqtrade.exchange.check_exchange - INFO - Exchange "binance" is officially supported by the Freqtrade development team.
2025-04-25 08:34:43,239 - freqtrade.configuration.configuration - INFO - Using pairlist from configuration.
2025-04-25 08:34:43,240 - freqtrade.configuration.config_validation - INFO - Validating configuration ...
2025-04-25 08:34:43,243 - freqtrade.exchange.exchange - INFO - Instance is running with dry_run enabled
2025-04-25 08:34:43,244 - freqtrade.exchange.exchange - INFO - Using CCXT 4.4.73
2025-04-25 08:34:43,272 - freqtrade.exchange.exchange - INFO - Using Exchange "Binance"
2025-04-25 08:34:43,273 - freqtrade.resolvers.exchange_resolver - INFO - Using resolved exchange 'Binance'...
2025-04-25 08:34:43,287 - freqtrade.resolvers.iresolver - INFO - Using resolved pairlist AlphaCoinSelectorPairList from 
'/Users/kaiyi/Work/develop/Code/freqtrade/freqtrade/plugins/pairlist/alpha_coin_selector.py'...
2025-04-25 08:34:43,288 - freqtrade.exchange.exchange - INFO - Markets were not loaded. Loading them now..
2025-04-25 08:34:45,303 - alpha_coin_selector - INFO - _pairlist: ['BTC/USDT', 'ETH/USDT', 'BNB/USDT', 'NEO/USDT', 'LTC/USDT', 'QTUM/USDT', 'ADA/USDT', 'XRP/USDT', 
'EOS/USDT', 'TUSD/USDT', 'IOTA/USDT', 'XLM/USDT', 'ONT/USDT', 'TRX/USDT', 'ETC/USDT', 'ICX/USDT', 'VET/USDT', 'USDC/USDT', 'LINK/USDT', 'ONG/USDT', 'HOT/USDT', 'ZIL/USDT', 
'ZRX/USDT', 'FET/USDT', 'BAT/USDT', 'ZEC/USDT', 'IOST/USDT', 'CELR/USDT', 'DASH/USDT', 'THETA/USDT', 'ENJ/USDT', 'ATOM/USDT', 'TFUEL/USDT', 'ONE/USDT', 'ALGO/USDT', 
'DOGE/USDT', 'DUSK/USDT', 'ANKR/USDT', 'WIN/USDT', 'COS/USDT', 'MTL/USDT', 'DENT/USDT', 'WAN/USDT', 'FUN/USDT', 'CVC/USDT', 'CHZ/USDT', 'BAND/USDT', 'XTZ/USDT', 'RVN/USDT', 
'HBAR/USDT', 'NKN/USDT', 'STX/USDT', 'KAVA/USDT', 'ARPA/USDT', 'IOTX/USDT', 'RLC/USDT', 'BCH/USDT', 'FTT/USDT', 'EUR/USDT', 'OGN/USDT', 'LSK/USDT', 'BNT/USDT', 'LTO/USDT', 
'MBL/USDT', 'COTI/USDT', 'STPT/USDT', 'DATA/USDT', 'SOL/USDT', 'CTSI/USDT', 'HIVE/USDT', 'CHR/USDT', 'ARDR/USDT', 'MDT/USDT', 'KNC/USDT', 'LRC/USDT', 'COMP/USDT', 'SC/USDT',
'ZEN/USDT', 'SNX/USDT', 'VTHO/USDT', 'DGB/USDT', 'SXP/USDT', 'MKR/USDT', 'DCR/USDT', 'STORJ/USDT', 'MANA/USDT', 'YFI/USDT', 'KMD/USDT', 'JST/USDT', 'CRV/USDT', 'SAND/USDT', 
'NMR/USDT', 'DOT/USDT', 'LUNA/USDT', 'RSR/USDT', 'PAXG/USDT', 'TRB/USDT', 'SUSHI/USDT', 'KSM/USDT', 'EGLD/USDT', 'DIA/USDT', 'RUNE/USDT', 'FIO/USDT', 'UMA/USDT', 'BEL/USDT',
'WING/USDT', 'UNI/USDT', 'OXT/USDT', 'SUN/USDT', 'AVAX/USDT', 'FLM/USDT', 'UTK/USDT', 'XVS/USDT', 'ALPHA/USDT', 'AAVE/USDT', 'NEAR/USDT', 'FIL/USDT', 'INJ/USDT', 
'AUDIO/USDT', 'CTK/USDT', 'AXS/USDT', 'STRAX/USDT', 'ROSE/USDT', 'AVA/USDT', 'SKL/USDT', 'GRT/USDT', 'JUV/USDT', 'PSG/USDT', '1INCH/USDT', 'OG/USDT', 'ATM/USDT', 'ASR/USDT',
'CELO/USDT', 'RIF/USDT', 'TRU/USDT', 'CKB/USDT', 'TWT/USDT', 'SFP/USDT', 'DODO/USDT', 'CAKE/USDT', 'ACM/USDT', 'FIS/USDT', 'OM/USDT', 'POND/USDT', 'DEGO/USDT', 'ALICE/USDT',
'PERP/USDT', 'SUPER/USDT', 'CFX/USDT', 'TKO/USDT', 'PUNDIX/USDT', 'TLM/USDT', 'BAR/USDT', 'FORTH/USDT', 'BAKE/USDT', 'SLP/USDT', 'SHIB/USDT', 'ICP/USDT', 'AR/USDT', 
'MASK/USDT', 'LPT/USDT', 'XVG/USDT', 'ATA/USDT', 'GTC/USDT', 'PHA/USDT', 'MLN/USDT', 'DEXE/USDT', 'C98/USDT', 'QNT/USDT', 'FLOW/USDT', 'MINA/USDT', 'RAY/USDT', 'FARM/USDT', 
'ALPACA/USDT', 'QUICK/USDT', 'MBOX/USDT', 'REQ/USDT', 'GHST/USDT', 'WAXP/USDT', 'GNO/USDT', 'XEC/USDT', 'DYDX/USDT', 'IDEX/USDT', 'USDP/USDT', 'GALA/USDT', 'ILV/USDT', 
'YGG/USDT', 'SYS/USDT', 'DF/USDT', 'FIDA/USDT', 'AGLD/USDT', 'RAD/USDT', 'RARE/USDT', 'LAZIO/USDT', 'CHESS/USDT', 'ADX/USDT', 'AUCTION/USDT', 'MOVR/USDT', 'CITY/USDT', 
'ENS/USDT', 'QI/USDT', 'PORTO/USDT', 'POWR/USDT', 'JASMY/USDT', 'AMP/USDT', 'PYR/USDT', 'ALCX/USDT', 'SANTOS/USDT', 'BICO/USDT', 'FLUX/USDT', 'FXS/USDT', 'VOXEL/USDT', 
'HIGH/USDT', 'CVX/USDT', 'PEOPLE/USDT', 'SPELL/USDT', 'JOE/USDT', 'ACH/USDT', 'IMX/USDT', 'GLMR/USDT', 'LOKA/USDT', 'SCRT/USDT', 'API3/USDT', 'BTTC/USDT', 'ACA/USDT', 
'XNO/USDT', 'WOO/USDT', 'ALPINE/USDT', 'T/USDT', 'ASTR/USDT', 'GMT/USDT', 'KDA/USDT', 'APE/USDT', 'BSW/USDT', 'BIFI/USDT', 'STEEM/USDT', 'NEXO/USDT', 'REI/USDT', 'LDO/USDT',
'OP/USDT', 'LEVER/USDT', 'STG/USDT', 'LUNC/USDT', 'GMX/USDT', 'POLYX/USDT', 'APT/USDT', 'OSMO/USDT', 'HFT/USDT', 'PHB/USDT', 'HOOK/USDT', 'MAGIC/USDT', 'HIFI/USDT', 
'RPL/USDT', 'GNS/USDT', 'SYN/USDT', 'VIB/USDT', 'SSV/USDT', 'LQTY/USDT', 'USTC/USDT', 'GAS/USDT', 'GLM/USDT', 'PROM/USDT', 'QKC/USDT', 'ID/USDT', 'ARB/USDT', 'RDNT/USDT', 
'WBTC/USDT', 'EDU/USDT', 'SUI/USDT', 'PEPE/USDT', 'FLOKI/USDT', 'MAV/USDT', 'PENDLE/USDT', 'ARKM/USDT', 'WBETH/USDT', 'WLD/USDT', 'FDUSD/USDT', 'SEI/USDT', 'CYBER/USDT', 
'ARK/USDT', 'IQ/USDT', 'NTRN/USDT', 'TIA/USDT', 'MEME/USDT', 'ORDI/USDT', 'BEAMX/USDT', 'PIVX/USDT', 'VIC/USDT', 'BLUR/USDT', 'VANRY/USDT', 'AEUR/USDT', 'JTO/USDT', 
'1000SATS/USDT', 'BONK/USDT', 'ACE/USDT', 'NFP/USDT', 'AI/USDT', 'XAI/USDT', 'MANTA/USDT', 'ALT/USDT', 'JUP/USDT', 'PYTH/USDT', 'RONIN/USDT', 'DYM/USDT', 'PIXEL/USDT', 
'STRK/USDT', 'PORTAL/USDT', 'PDA/USDT', 'AXL/USDT', 'WIF/USDT', 'METIS/USDT', 'AEVO/USDT', 'BOME/USDT', 'ETHFI/USDT', 'ENA/USDT', 'W/USDT', 'TNSR/USDT', 'SAGA/USDT', 
'TAO/USDT', 'OMNI/USDT', 'REZ/USDT', 'BB/USDT', 'NOT/USDT', 'IO/USDT', 'ZK/USDT', 'LISTA/USDT', 'ZRO/USDT', 'G/USDT', 'BANANA/USDT', 'RENDER/USDT', 'TON/USDT', 'DOGS/USDT', 
'EURI/USDT', 'SLF/USDT', 'POL/USDT', 'NEIRO/USDT', 'TURBO/USDT', '1MBABYDOGE/USDT', 'CATI/USDT', 'HMSTR/USDT', 'EIGEN/USDT', 'SCR/USDT', 'BNSOL/USDT', 'LUMIA/USDT', 
'KAIA/USDT', 'COW/USDT', 'CETUS/USDT', 'PNUT/USDT', 'ACT/USDT', 'USUAL/USDT', 'THE/USDT', 'ACX/USDT', 'ORCA/USDT', 'MOVE/USDT', 'ME/USDT', 'VELODROME/USDT', 'VANA/USDT', 
'1000CAT/USDT', 'PENGU/USDT', 'BIO/USDT', 'D/USDT', 'AIXBT/USDT', 'CGPT/USDT', 'COOKIE/USDT', 'S/USDT', 'SOLV/USDT', 'TRUMP/USDT', 'ANIME/USDT', 'BERA/USDT', 
'1000CHEEMS/USDT', 'TST/USDT', 'LAYER/USDT', 'HEI/USDT', 'KAITO/USDT', 'SHELL/USDT', 'RED/USDT', 'GPS/USDT', 'EPIC/USDT', 'BMT/USDT', 'FORM/USDT', 'XUSD/USDT', 'NIL/USDT', 
'PARTI/USDT', 'MUBARAK/USDT', 'TUT/USDT', 'BROCCOLI714/USDT', 'BANANAS31/USDT', 'GUN/USDT', 'BABY/USDT', 'ONDO/USDT', 'BIGTIME/USDT', 'VIRTUAL/USDT', 'KERNEL/USDT', 
'WCT/USDT', 'HYPER/USDT', 'INIT/USDT']
2025-04-25 08:34:45,319 - alpha_coin_selector - INFO - Pair TRB/USDT in your blacklist. Removing it from whitelist...
2025-04-25 08:34:45,326 - alpha_coin_selector - INFO - market: {'id': 'BTCUSDT', 'lowercaseId': 'btcusdt', 'symbol': 'BTC/USDT', 'base': 'BTC', 'quote': 'USDT', 'settle': 
None, 'baseId': 'BTC', 'quoteId': 'USDT', 'settleId': None, 'type': 'spot', 'spot': True, 'margin': True, 'swap': False, 'future': False, 'option': False, 'index': None, 
'active': True, 'contract': False, 'linear': None, 'inverse': None, 'subType': None, 'taker': 0.001, 'maker': 0.001, 'contractSize': None, 'expiry': None, 'expiryDatetime': 
None, 'strike': None, 'optionType': None, 'precision': {'amount': 1e-05, 'price': 0.01, 'cost': None, 'base': 1e-08, 'quote': 1e-08}, 'limits': {'leverage': {'min': None, 
'max': None}, 'amount': {'min': 1e-05, 'max': 9000.0}, 'price': {'min': 0.01, 'max': 1000000.0}, 'cost': {'min': 5.0, 'max': 9000000.0}, 'market': {'min': 0.0, 'max': 
117.95510179}}, 'marginModes': {'cross': False, 'isolated': False}, 'created': None, 'info': {'symbol': 'BTCUSDT', 'status': 'TRADING', 'baseAsset': 'BTC', 
'baseAssetPrecision': 8, 'quoteAsset': 'USDT', 'quotePrecision': 8, 'quoteAssetPrecision': 8, 'baseCommissionPrecision': 8, 'quoteCommissionPrecision': 8, 'orderTypes': 
['LIMIT', 'LIMIT_MAKER', 'MARKET', 'STOP_LOSS', 'STOP_LOSS_LIMIT', 'TAKE_PROFIT', 'TAKE_PROFIT_LIMIT'], 'icebergAllowed': True, 'ocoAllowed': True, 'otoAllowed': True, 
'quoteOrderQtyMarketAllowed': True, 'allowTrailingStop': True, 'cancelReplaceAllowed': True, 'amendAllowed': False, 'isSpotTradingAllowed': True, 'isMarginTradingAllowed': 
True, 'filters': [{'filterType': 'PRICE_FILTER', 'minPrice': '0.01000000', 'maxPrice': '1000000.00000000', 'tickSize': '0.01000000'}, {'filterType': 'LOT_SIZE', 'minQty': 
'0.00001000', 'maxQty': '9000.00000000', 'stepSize': '0.00001000'}, {'filterType': 'ICEBERG_PARTS', 'limit': 10}, {'filterType': 'MARKET_LOT_SIZE', 'minQty': '0.00000000', 
'maxQty': '117.95510179', 'stepSize': '0.00000000'}, {'filterType': 'TRAILING_DELTA', 'minTrailingAboveDelta': 10, 'maxTrailingAboveDelta': 2000, 'minTrailingBelowDelta': 
10, 'maxTrailingBelowDelta': 2000}, {'filterType': 'PERCENT_PRICE_BY_SIDE', 'bidMultiplierUp': '5', 'bidMultiplierDown': '0.2', 'askMultiplierUp': '5', 'askMultiplierDown': 
'0.2', 'avgPriceMins': 5}, {'filterType': 'NOTIONAL', 'minNotional': '5.00000000', 'applyMinToMarket': True, 'maxNotional': '9000000.00000000', 'applyMaxToMarket': False, 
'avgPriceMins': 5}, {'filterType': 'MAX_NUM_ORDERS', 'maxNumOrders': 200}, {'filterType': 'MAX_NUM_ALGO_ORDERS', 'maxNumAlgoOrders': 5}], 'permissions': [], 
'permissionSets': [['SPOT', 'MARGIN', 'TRD_GRP_004', 'TRD_GRP_005', 'TRD_GRP_006', 'TRD_GRP_015', 'TRD_GRP_016', 'TRD_GRP_017', 'TRD_GRP_018', 'TRD_GRP_019', 'TRD_GRP_020', 
'TRD_GRP_021', 'TRD_GRP_022', 'TRD_GRP_023', 'TRD_GRP_024', 'TRD_GRP_025', 'TRD_GRP_049', 'TRD_GRP_050', 'TRD_GRP_051', 'TRD_GRP_052', 'TRD_GRP_053', 'TRD_GRP_054', 
'TRD_GRP_055', 'TRD_GRP_056', 'TRD_GRP_057', 'TRD_GRP_058', 'TRD_GRP_059', 'TRD_GRP_060', 'TRD_GRP_061', 'TRD_GRP_062', 'TRD_GRP_063', 'TRD_GRP_064', 'TRD_GRP_065', 
'TRD_GRP_066', 'TRD_GRP_067', 'TRD_GRP_068', 'TRD_GRP_069', 'TRD_GRP_070', 'TRD_GRP_071', 'TRD_GRP_072', 'TRD_GRP_073', 'TRD_GRP_074', 'TRD_GRP_075', 'TRD_GRP_076', 
'TRD_GRP_077', 'TRD_GRP_078', 'TRD_GRP_079', 'TRD_GRP_080', 'TRD_GRP_081', 'TRD_GRP_082', 'TRD_GRP_083', 'TRD_GRP_084', 'TRD_GRP_085', 'TRD_GRP_086', 'TRD_GRP_087', 
'TRD_GRP_088', 'TRD_GRP_089', 'TRD_GRP_090', 'TRD_GRP_091', 'TRD_GRP_092', 'TRD_GRP_093', 'TRD_GRP_094', 'TRD_GRP_095', 'TRD_GRP_096', 'TRD_GRP_097', 'TRD_GRP_098', 
'TRD_GRP_099', 'TRD_GRP_100', 'TRD_GRP_101', 'TRD_GRP_102', 'TRD_GRP_103', 'TRD_GRP_104', 'TRD_GRP_105', 'TRD_GRP_106', 'TRD_GRP_107', 'TRD_GRP_108', 'TRD_GRP_109', 
'TRD_GRP_110', 'TRD_GRP_111', 'TRD_GRP_112', 'TRD_GRP_113', 'TRD_GRP_114', 'TRD_GRP_115', 'TRD_GRP_116', 'TRD_GRP_117', 'TRD_GRP_118', 'TRD_GRP_119', 'TRD_GRP_120', 
'TRD_GRP_121', 'TRD_GRP_122', 'TRD_GRP_123', 'TRD_GRP_124', 'TRD_GRP_125', 'TRD_GRP_126', 'TRD_GRP_127', 'TRD_GRP_128', 'TRD_GRP_129', 'TRD_GRP_130', 'TRD_GRP_131', 
'TRD_GRP_132', 'TRD_GRP_133', 'TRD_GRP_134', 'TRD_GRP_135', 'TRD_GRP_136', 'TRD_GRP_137', 'TRD_GRP_138', 'TRD_GRP_139', 'TRD_GRP_140', 'TRD_GRP_141', 'TRD_GRP_142', 
'TRD_GRP_143', 'TRD_GRP_144', 'TRD_GRP_145', 'TRD_GRP_146', 'TRD_GRP_147', 'TRD_GRP_148', 'TRD_GRP_149', 'TRD_GRP_150', 'TRD_GRP_151', 'TRD_GRP_152', 'TRD_GRP_153', 
'TRD_GRP_154', 'TRD_GRP_155', 'TRD_GRP_156', 'TRD_GRP_157', 'TRD_GRP_158', 'TRD_GRP_159', 'TRD_GRP_160', 'TRD_GRP_161', 'TRD_GRP_162', 'TRD_GRP_163', 'TRD_GRP_164', 
'TRD_GRP_165', 'TRD_GRP_166', 'TRD_GRP_167', 'TRD_GRP_168', 'TRD_GRP_169', 'TRD_GRP_170', 'TRD_GRP_171', 'TRD_GRP_172', 'TRD_GRP_173', 'TRD_GRP_174', 'TRD_GRP_175', 
'TRD_GRP_176', 'TRD_GRP_177', 'TRD_GRP_178', 'TRD_GRP_179', 'TRD_GRP_180', 'TRD_GRP_181', 'TRD_GRP_182', 'TRD_GRP_183', 'TRD_GRP_184', 'TRD_GRP_185', 'TRD_GRP_186', 
'TRD_GRP_187', 'TRD_GRP_188', 'TRD_GRP_189', 'TRD_GRP_190', 'TRD_GRP_191', 'TRD_GRP_192', 'TRD_GRP_193', 'TRD_GRP_194', 'TRD_GRP_195', 'TRD_GRP_196', 'TRD_GRP_197', 
'TRD_GRP_198', 'TRD_GRP_199', 'TRD_GRP_200', 'TRD_GRP_201', 'TRD_GRP_202', 'TRD_GRP_203', 'TRD_GRP_204', 'TRD_GRP_205', 'TRD_GRP_206', 'TRD_GRP_207', 'TRD_GRP_208', 
'TRD_GRP_209', 'TRD_GRP_210', 'TRD_GRP_211', 'TRD_GRP_212', 'TRD_GRP_213', 'TRD_GRP_214', 'TRD_GRP_215', 'TRD_GRP_216', 'TRD_GRP_217', 'TRD_GRP_218', 'TRD_GRP_219', 
'TRD_GRP_220', 'TRD_GRP_221', 'TRD_GRP_222', 'TRD_GRP_223', 'TRD_GRP_224', 'TRD_GRP_225', 'TRD_GRP_226', 'TRD_GRP_227', 'TRD_GRP_228', 'TRD_GRP_229', 'TRD_GRP_230', 
'TRD_GRP_231', 'TRD_GRP_232', 'TRD_GRP_233', 'TRD_GRP_234', 'TRD_GRP_235', 'TRD_GRP_236']], 'defaultSelfTradePreventionMode': 'EXPIRE_MAKER', 
'allowedSelfTradePreventionModes': ['EXPIRE_TAKER', 'EXPIRE_MAKER', 'EXPIRE_BOTH']}, 'tierBased': False, 'percentage': True, 'feeSide': 'get'}
2025-04-25 08:34:45,338 - freqtrade - ERROR - Fatal exception!
Traceback (most recent call last):
  File "/Users/kaiyi/Work/develop/Code/freqtrade/freqtrade/main.py", line 48, in main
    return_code = args["func"](args)
                  ^^^^^^^^^^^^^^^^^^
  File "/Users/kaiyi/Work/develop/Code/freqtrade/freqtrade/commands/pairlist_commands.py", line 33, in start_test_pairlist
    pairlists.refresh_pairlist()
  File "/Users/kaiyi/Work/develop/Code/freqtrade/freqtrade/plugins/pairlistmanager.py", line 135, in refresh_pairlist
    pairlist = self._pairlist_handlers[0].gen_pairlist(tickers)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kaiyi/Work/develop/Code/freqtrade/freqtrade/plugins/pairlist/alpha_coin_selector.py", line 96, in gen_pairlist
    pairlist = self.filter_pairlist(_pairlist, tickers)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kaiyi/Work/develop/Code/freqtrade/freqtrade/plugins/pairlist/alpha_coin_selector.py", line 107, in filter_pairlist
    if market and self.filter_coin(symbol, market):
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kaiyi/Work/develop/Code/freqtrade/freqtrade/plugins/pairlist/alpha_coin_selector.py", line 120, in filter_coin
    if market['volume24h'] < 2000000:
       ~~~~~~^^^^^^^^^^^^^
KeyError: 'volume24h'
(.venv) (base) ➜  freqtrade git:(develop) ✗ 

market数据结构:

{
  "id": "BTCUSDT",
  "lowercaseId": "btcusdt",
  "symbol": "BTC/USDT",
  "base": "BTC",
  "quote": "USDT",
  "settle": null,
  "baseId": "BTC",
  "quoteId": "USDT",
  "settleId": null,
  "type": "spot",
  "spot": true,
  "margin": true,
  "swap": false,
  "future": false,
  "option": false,
  "index": null,
  "active": true,
  "contract": false,
  "linear": null,
  "inverse": null,
  "subType": null,
  "taker": 0.001,
  "maker": 0.001,
  "contractSize": null,
  "expiry": null,
  "expiryDatetime": null,
  "strike": null,
  "optionType": null,
  "precision": {
    "amount": 0.00001,
    "price": 0.01,
    "cost": null,
    "base": 0.00000001,
    "quote": 0.00000001
  },
  "limits": {
    "leverage": {
      "min": null,
      "max": null
    },
    "amount": {
      "min": 0.00001,
      "max": 9000.0
    },
    "price": {
      "min": 0.01,
      "max": 1000000.0
    },
    "cost": {
      "min": 5.0,
      "max": 9000000.0
    },
    "market": {
      "min": 0.0,
      "max": 117.95510179
    }
  },
  "marginModes": {
    "cross": false,
    "isolated": false
  },
  "created": null,
  "info": {
    "symbol": "BTCUSDT",
    "status": "TRADING",
    "baseAsset": "BTC",
    "baseAssetPrecision": 8,
    "quoteAsset": "USDT",
    "quotePrecision": 8,
    "quoteAssetPrecision": 8,
    "baseCommissionPrecision": 8,
    "quoteCommissionPrecision": 8,
    "orderTypes": [
      "LIMIT",
      "LIMIT_MAKER",
      "MARKET",
      "STOP_LOSS",
      "STOP_LOSS_LIMIT",
      "TAKE_PROFIT",
      "TAKE_PROFIT_LIMIT"
    ],
    "icebergAllowed": true,
    "ocoAllowed": true,
    "otoAllowed": true,
    "quoteOrderQtyMarketAllowed": true,
    "allowTrailingStop": true,
    "cancelReplaceAllowed": true,
    "amendAllowed": false,
    "isSpotTradingAllowed": true,
    "isMarginTradingAllowed": true,
    "filters": [
      {
        "filterType": "PRICE_FILTER",
        "minPrice": "0.01000000",
        "maxPrice": "1000000.00000000",
        "tickSize": "0.01000000"
      },
      {
        "filterType": "LOT_SIZE",
        "minQty": "0.00001000",
        "maxQty": "9000.00000000",
        "stepSize": "0.00001000"
      },
      {
        "filterType": "ICEBERG_PARTS",
        "limit": 10
      },
      {
        "filterType": "MARKET_LOT_SIZE",
        "minQty": "0.00000000",
        "maxQty": "117.95510179",
        "stepSize": "0.00000000"
      },
      {
        "filterType": "TRAILING_DELTA",
        "minTrailingAboveDelta": 10,
        "maxTrailingAboveDelta": 2000,
        "minTrailingBelowDelta": 10,
        "maxTrailingBelowDelta": 2000
      },
      {
        "filterType": "PERCENT_PRICE_BY_SIDE",
        "bidMultiplierUp": "5",
        "bidMultiplierDown": "0.2",
        "askMultiplierUp": "5",
        "askMultiplierDown": "0.2",
        "avgPriceMins": 5
      },
      {
        "filterType": "NOTIONAL",
        "minNotional": "5.00000000",
        "applyMinToMarket": true,
        "maxNotional": "9000000.00000000",
        "applyMaxToMarket": false,
        "avgPriceMins": 5
      },
      {
        "filterType": "MAX_NUM_ORDERS",
        "maxNumOrders": 200
      },
      {
        "filterType": "MAX_NUM_ALGO_ORDERS",
        "maxNumAlgoOrders": 5
      }
    ],
    "permissions": [],
    "permissionSets": [
      [
        "SPOT",
        "MARGIN",
        "TRD_GRP_004",
        "TRD_GRP_005",
        "TRD_GRP_006",
        "TRD_GRP_015",
        "TRD_GRP_016",
        "TRD_GRP_017",
        "TRD_GRP_018",
        "TRD_GRP_019",
        "TRD_GRP_020",
        "TRD_GRP_021",
        "TRD_GRP_022",
        "TRD_GRP_023",
        "TRD_GRP_024",
        "TRD_GRP_025",
        "TRD_GRP_049",
        "TRD_GRP_050",
        "TRD_GRP_051",
        "TRD_GRP_052",
        "TRD_GRP_053",
        "TRD_GRP_054",
        "TRD_GRP_055",
        "TRD_GRP_056",
        "TRD_GRP_057",
        "TRD_GRP_058",
        "TRD_GRP_059",
        "TRD_GRP_060",
        "TRD_GRP_061",
        "TRD_GRP_062",
        "TRD_GRP_063",
        "TRD_GRP_064",
        "TRD_GRP_065",
        "TRD_GRP_066",
        "TRD_GRP_067",
        "TRD_GRP_068",
        "TRD_GRP_069",
        "TRD_GRP_070",
        "TRD_GRP_071",
        "TRD_GRP_072",
        "TRD_GRP_073",
        "TRD_GRP_074",
        "TRD_GRP_075",
        "TRD_GRP_076",
        "TRD_GRP_077",
        "TRD_GRP_078",
        "TRD_GRP_079",
        "TRD_GRP_080",
        "TRD_GRP_081",
        "TRD_GRP_082",
        "TRD_GRP_083",
        "TRD_GRP_084",
        "TRD_GRP_085",
        "TRD_GRP_086",
        "TRD_GRP_087",
        "TRD_GRP_088",
        "TRD_GRP_089",
        "TRD_GRP_090",
        "TRD_GRP_091",
        "TRD_GRP_092",
        "TRD_GRP_093",
        "TRD_GRP_094",
        "TRD_GRP_095",
        "TRD_GRP_096",
        "TRD_GRP_097",
        "TRD_GRP_098",
        "TRD_GRP_099",
        "TRD_GRP_100",
        "TRD_GRP_101",
        "TRD_GRP_102",
        "TRD_GRP_103",
        "TRD_GRP_104",
        "TRD_GRP_105",
        "TRD_GRP_106",
        "TRD_GRP_107",
        "TRD_GRP_108",
        "TRD_GRP_109",
        "TRD_GRP_110",
        "TRD_GRP_111",
        "TRD_GRP_112",
        "TRD_GRP_113",
        "TRD_GRP_114",
        "TRD_GRP_115",
        "TRD_GRP_116",
        "TRD_GRP_117",
        "TRD_GRP_118",
        "TRD_GRP_119",
        "TRD_GRP_120",
        "TRD_GRP_121",
        "TRD_GRP_122",
        "TRD_GRP_123",
        "TRD_GRP_124",
        "TRD_GRP_125",
        "TRD_GRP_126",
        "TRD_GRP_127",
        "TRD_GRP_128",
        "TRD_GRP_129",
        "TRD_GRP_130",
        "TRD_GRP_131",
        "TRD_GRP_132",
        "TRD_GRP_133",
        "TRD_GRP_134",
        "TRD_GRP_135",
        "TRD_GRP_136",
        "TRD_GRP_137",
        "TRD_GRP_138",
        "TRD_GRP_139",
        "TRD_GRP_140",
        "TRD_GRP_141",
        "TRD_GRP_142",
        "TRD_GRP_143",
        "TRD_GRP_144",
        "TRD_GRP_145",
        "TRD_GRP_146",
        "TRD_GRP_147",
        "TRD_GRP_148",
        "TRD_GRP_149",
        "TRD_GRP_150",
        "TRD_GRP_151",
        "TRD_GRP_152",
        "TRD_GRP_153",
        "TRD_GRP_154",
        "TRD_GRP_155",
        "TRD_GRP_156",
        "TRD_GRP_157",
        "TRD_GRP_158",
        "TRD_GRP_159",
        "TRD_GRP_160",
        "TRD_GRP_161",
        "TRD_GRP_162",
        "TRD_GRP_163",
        "TRD_GRP_164",
        "TRD_GRP_165",
        "TRD_GRP_166",
        "TRD_GRP_167",
        "TRD_GRP_168",
        "TRD_GRP_169",
        "TRD_GRP_170",
        "TRD_GRP_171",
        "TRD_GRP_172",
        "TRD_GRP_173",
        "TRD_GRP_174",
        "TRD_GRP_175",
        "TRD_GRP_176",
        "TRD_GRP_177",
        "TRD_GRP_178",
        "TRD_GRP_179",
        "TRD_GRP_180",
        "TRD_GRP_181",
        "TRD_GRP_182",
        "TRD_GRP_183",
        "TRD_GRP_184",
        "TRD_GRP_185",
        "TRD_GRP_186",
        "TRD_GRP_187",
        "TRD_GRP_188",
        "TRD_GRP_189",
        "TRD_GRP_190",
        "TRD_GRP_191",
        "TRD_GRP_192",
        "TRD_GRP_193",
        "TRD_GRP_194",
        "TRD_GRP_195",
        "TRD_GRP_196",
        "TRD_GRP_197",
        "TRD_GRP_198",
        "TRD_GRP_199",
        "TRD_GRP_200",
        "TRD_GRP_201",
        "TRD_GRP_202",
        "TRD_GRP_203",
        "TRD_GRP_204",
        "TRD_GRP_205",
        "TRD_GRP_206",
        "TRD_GRP_207",
        "TRD_GRP_208",
        "TRD_GRP_209",
        "TRD_GRP_210",
        "TRD_GRP_211",
        "TRD_GRP_212",
        "TRD_GRP_213",
        "TRD_GRP_214",
        "TRD_GRP_215",
        "TRD_GRP_216",
        "TRD_GRP_217",
        "TRD_GRP_218",
        "TRD_GRP_219",
        "TRD_GRP_220",
        "TRD_GRP_221",
        "TRD_GRP_222",
        "TRD_GRP_223",
        "TRD_GRP_224",
        "TRD_GRP_225",
        "TRD_GRP_226",
        "TRD_GRP_227",
        "TRD_GRP_228",
        "TRD_GRP_229",
        "TRD_GRP_230",
        "TRD_GRP_231",
        "TRD_GRP_232",
        "TRD_GRP_233",
        "TRD_GRP_234",
        "TRD_GRP_235",
        "TRD_GRP_236"
      ]
    ],
    "defaultSelfTradePreventionMode": "EXPIRE_MAKER",
    "allowedSelfTradePreventionModes": [
      "EXPIRE_TAKER",
      "EXPIRE_MAKER",
      "EXPIRE_BOTH"
    ]
  },
  "tierBased": false,
  "percentage": true,
  "feeSide": "get"
}

打印策略输出

freqtrade trade --strategy MyStrategy \
--config user_data/config/dual_ma_config.json

输出策略的 dataframe 结构:

`-0.1`\n*Position adjustment:* `Off`\n*Timeframe:* `4h`\n*Strategy:* `MyStrategy`"}
2025-05-11 18:22:52,108 - freqtrade.rpc.rpc_manager - INFO - Sending rpc message: {'type': startup, 'status': "Searching for USDT pairs to buy and sell based on [{'StaticPairList': 'StaticPairList'}]"}
打印 populate_indicators:
                          date      open      high       low     close     volume        rsi
0    2024-09-03 12:00:00+00:00   59038.5   59332.9   57530.1   57695.1  88841.444        NaN
1    2024-09-03 16:00:00+00:00   57695.1   58250.0   57560.7   58020.9  42995.514        NaN
2    2024-09-03 20:00:00+00:00   58021.0   58217.6   57320.0   57451.9  22905.401        NaN
3    2024-09-04 00:00:00+00:00   57452.0   57920.0   55555.0   56632.9  96559.930        NaN
4    2024-09-04 04:00:00+00:00   56632.9   56847.2   56107.9   56717.0  36160.820        NaN
...                        ...       ...       ...       ...       ...        ...        ...
1494 2025-05-10 12:00:00+00:00  103374.7  103781.1  103038.7  103102.6  13607.261  68.350624
1495 2025-05-10 16:00:00+00:00  103102.6  103589.0  102940.0  103148.6  14747.802  68.549707
1496 2025-05-10 20:00:00+00:00  103148.7  105000.1  103016.2  104788.8  30328.721  74.668379
1497 2025-05-11 00:00:00+00:00  104788.8  104950.0  103406.3  103947.8  27276.827  67.425059
1498 2025-05-11 04:00:00+00:00  103947.8  104363.9  103283.3  103327.9  18978.685  62.604300

[1499 rows x 7 columns]
--------- 打印 populate_entry_trend:
                          date      open      high       low     close     volume        rsi enter_tag  enter_long
0    2024-09-03 12:00:00+00:00   59038.5   59332.9   57530.1   57695.1  88841.444        NaN                   NaN
1    2024-09-03 16:00:00+00:00   57695.1   58250.0   57560.7   58020.9  42995.514        NaN                   NaN
2    2024-09-03 20:00:00+00:00   58021.0   58217.6   57320.0   57451.9  22905.401        NaN                   NaN
3    2024-09-04 00:00:00+00:00   57452.0   57920.0   55555.0   56632.9  96559.930        NaN                   NaN
4    2024-09-04 04:00:00+00:00   56632.9   56847.2   56107.9   56717.0  36160.820        NaN                   NaN
...                        ...       ...       ...       ...       ...        ...        ...       ...         ...
1494 2025-05-10 12:00:00+00:00  103374.7  103781.1  103038.7  103102.6  13607.261  68.350624                   NaN
1495 2025-05-10 16:00:00+00:00  103102.6  103589.0  102940.0  103148.6  14747.802  68.549707                   NaN
1496 2025-05-10 20:00:00+00:00  103148.7  105000.1  103016.2  104788.8  30328.721  74.668379                   NaN
1497 2025-05-11 00:00:00+00:00  104788.8  104950.0  103406.3  103947.8  27276.827  67.425059                   NaN
1498 2025-05-11 04:00:00+00:00  103947.8  104363.9  103283.3  103327.9  18978.685  62.604300                   NaN

[1499 rows x 9 columns]
--------- 打印 populate_exit_trend:
                          date      open      high       low     close     volume        rsi enter_tag  enter_long exit_tag  exit_long
0    2024-09-03 12:00:00+00:00   59038.5   59332.9   57530.1   57695.1  88841.444        NaN                   NaN                 NaN
1    2024-09-03 16:00:00+00:00   57695.1   58250.0   57560.7   58020.9  42995.514        NaN                   NaN                 NaN
2    2024-09-03 20:00:00+00:00   58021.0   58217.6   57320.0   57451.9  22905.401        NaN                   NaN                 NaN
3    2024-09-04 00:00:00+00:00   57452.0   57920.0   55555.0   56632.9  96559.930        NaN                   NaN                 NaN
4    2024-09-04 04:00:00+00:00   56632.9   56847.2   56107.9   56717.0  36160.820        NaN                   NaN                 NaN
...                        ...       ...       ...       ...       ...        ...        ...       ...         ...      ...        ...
1494 2025-05-10 12:00:00+00:00  103374.7  103781.1  103038.7  103102.6  13607.261  68.350624                   NaN                 NaN
1495 2025-05-10 16:00:00+00:00  103102.6  103589.0  102940.0  103148.6  14747.802  68.549707                   NaN                 NaN
1496 2025-05-10 20:00:00+00:00  103148.7  105000.1  103016.2  104788.8  30328.721  74.668379                   NaN                 1.0
1497 2025-05-11 00:00:00+00:00  104788.8  104950.0  103406.3  103947.8  27276.827  67.425059                   NaN                 NaN
1498 2025-05-11 04:00:00+00:00  103947.8  104363.9  103283.3  103327.9  18978.685  62.604300                   NaN                 NaN

[1499 rows x 11 columns]
2025-05-11 18:22:57,111 - freqtrade.worker - INFO - Bot heartbeat. PID=23507, version='2025.4-dev-82cd343fc', state='RUNNING'
2025-05-11 18:23:57,158 - freqtrade.worker - INFO - Bot heartbeat. PID=23507, version='2025.4-dev-82cd343fc', state='RUNNING'

为者常成,行者常至