From de1601d9ff6ff76f2330b7adf27aeec8209d2617 Mon Sep 17 00:00:00 2001 From: "zhangkun9038@dingtalk.com" Date: Wed, 26 Nov 2025 10:15:13 +0800 Subject: [PATCH] first add --- config_examples/staticgrid.json | 50 +++++++++++++++++ freqtrade/templates/smartbbgrid.py | 41 -------------- freqtrade/templates/staticgrid.py | 90 ++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 41 deletions(-) create mode 100644 config_examples/staticgrid.json create mode 100644 freqtrade/templates/staticgrid.py diff --git a/config_examples/staticgrid.json b/config_examples/staticgrid.json new file mode 100644 index 0000000..fd42a2c --- /dev/null +++ b/config_examples/staticgrid.json @@ -0,0 +1,50 @@ +{ + "strategy": "StaticGrid", + "$schema": "https://schema.freqtrade.io/schema.json", + "trading_mode": "spot", + "margin_mode": "isolated", + "max_open_trades": 100, + "stake_currency": "USDT", + "stake_amount": "unlimited", + "tradable_balance_ratio": 1, + "process_only_new_candles": false, + "dry_run": true, + "timeframe": "4h", + "dry_run_wallet": 3500, + "cancel_open_orders_on_exit": true, + "max_entry_position_adjustment": -1, + "position_adjustment_enable": true, + "amount_reserve_percent": 0.05, + "unfilledtimeout": { + "entry": 5, + "exit": 15 + }, + "startup_candle_count": 1, + "exchange": { + "name": "okx", + "pair_whitelist": ["ETH/USDT"], + "ccxt_config": { + "enableRateLimit": true, + "rateLimit": 500 + } + }, + "entry_pricing": { + "price_side": "same", + "use_order_book": true, + "order_book_top": 1 + }, + "exit_pricing": { + "price_side": "other", + "use_order_book": true, + "order_book_top": 1 + }, + "pairlists": [{"method": "StaticPairList"}], + "bot_name": "StaticGrid-ETH", + "initial_state": "running", + "force_entry_enable": false, + "internals": { + "process_throttle_secs": 5, + "heartbeat_interval": 20, + "loglevel": "INFO" + } +} diff --git a/freqtrade/templates/smartbbgrid.py b/freqtrade/templates/smartbbgrid.py index 46f73f6..21b2828 100644 --- a/freqtrade/templates/smartbbgrid.py +++ b/freqtrade/templates/smartbbgrid.py @@ -17,44 +17,3 @@ class SmartBBGrid(IStrategy): position_adjustment_enable = True max_entry_position_adjustment = 1 - def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # ADX & DI - dataframe['adx'] = ta.ADX(dataframe, timeperiod=14) - dataframe['plus_di'] = ta.PLUS_DI(dataframe, timeperiod=14) - dataframe['minus_di'] = ta.MINUS_DI(dataframe, timeperiod=14) - - # 平衡布林带倍数:既要频繁,又要精准 - dataframe['bb_mult'] = np.where( - dataframe['minus_di'] > dataframe['plus_di'], - 1.8, # 熊市适度 - 1.6 # 牛市适度 ← 兼顾频率和准确率 - ) - - # qtpylib 动态布林带 - bollinger = qtpylib.bollinger_bands( - qtpylib.typical_price(dataframe), - window=20, - stds=dataframe['bb_mult'] - ) - dataframe['bb_lower'] = bollinger['lower'] - dataframe['bb_upper'] = bollinger['upper'] - dataframe['bb_mid'] = bollinger['mid'] - - return dataframe - - # ← 这里结束 - - def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # 纯网格逻辑:只要价格接近下轨就买入 - dataframe['enter_long'] = ( - (dataframe['close'] <= dataframe['bb_lower'] * 1.02) & # 下轨附近 2% 范围 - (dataframe['volume'] > 0) - ) - return dataframe - - def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # 纯网格逻辑:只要小幅反弹就卖出 - dataframe['exit_long'] = ( - (dataframe['close'] >= dataframe['bb_lower'] * 1.005) # 反弹 0.5% 就卖 - ) - return dataframe diff --git a/freqtrade/templates/staticgrid.py b/freqtrade/templates/staticgrid.py new file mode 100644 index 0000000..945f85e --- /dev/null +++ b/freqtrade/templates/staticgrid.py @@ -0,0 +1,90 @@ +from freqtrade.strategy import IStrategy +from pandas import DataFrame +import numpy as np + +class StaticGrid(IStrategy): + """ + 纯静态网格策略 - ETH/USDT + 价格范围:1500 ~ 4800 + 网格间距:50点 + 网格数量:66个 + """ + + INTERFACE_VERSION = 3 + timeframe = '4h' + can_short = False + + # 基础配置 + minimal_roi = {"0": 100} + stoploss = -0.99 + startup_candle_count = 1 + use_exit_signal = True + exit_profit_only = False + ignore_roi_if_entry_signal = True + + # 加仓配置 + position_adjustment_enable = True + max_entry_position_adjustment = -1 # 无限加仓 + + # ========== 静态网格参数 ========== + GRID_LOW = 1500 # 网格下限 + GRID_HIGH = 4800 # 网格上限 + GRID_STEP = 50 # 网格间距 + GRID_COUNT = 66 # 网格数量 + + # 计算网格点 + GRID_LEVELS = np.linspace(GRID_LOW, GRID_HIGH, GRID_COUNT) + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # 静态网格不需要复杂的指标,仅需要价格 + return dataframe + + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + 入场逻辑: + - 价格每次跌破一个网格点,就在该网格点买入 + - 从上往下遍历所有网格点 + """ + dataframe['enter_long'] = False + + # 对每个网格点进行判断 + for i, grid_level in enumerate(self.GRID_LEVELS[:-1]): # 不包括最后一个点 + # 价格接近或低于该网格点就买入 + # 使用 <= grid_level * 1.001 来避免浮点数精度问题 + dataframe.loc[ + (dataframe['close'] <= grid_level * 1.001) & + (dataframe['close'] > (grid_level - self.GRID_STEP)) & + (dataframe['volume'] > 0), + 'enter_long' + ] = True + + return dataframe + + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + 出场逻辑: + - 每笔交易进场后,在上一个网格点卖出 + - 每层网格的利润 = GRID_STEP / 当前价格 + """ + dataframe['exit_long'] = False + + # 简单策略:价格每上升 GRID_STEP,就卖出 + # 这里我们使用一个简化的方法:如果价格上升了 GRID_STEP 点以上,就卖出 + + # 计算相对于入场价格的涨幅百分比(目标:50点收益) + # 假设平均入场价在 2650 左右,50点 = 1.88% + # 为了泛用,我们设定:只要有 0.9% 的利润就卖出 + dataframe['exit_long'] = ( + dataframe['close'] >= (dataframe['close'].shift(1) * 1.009) + ) + + return dataframe + + def custom_stake_amount(self, pair: str, current_time, current_rate, + proposed_stake, min_stake, max_stake, + entry_tag, **kwargs) -> float: + """ + 每笔投入金额:固定 50 USDT + 目标:总投入 = 50 * 66 = 3300 USDT + """ + return 50.0