diff --git a/freqtrade/templates/staticgrid.py b/freqtrade/templates/staticgrid.py index 0abfa040..e4c5c942 100644 --- a/freqtrade/templates/staticgrid.py +++ b/freqtrade/templates/staticgrid.py @@ -1,6 +1,7 @@ # /freqtrade/user_data/strategies/StaticGrid.py from freqtrade.strategy import IStrategy from pandas import DataFrame +from typing import Optional import logging import sys @@ -36,12 +37,13 @@ class StaticGrid(IStrategy): def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Static Grid Entry Logic: + Static Grid Entry Logic using multiple enter_tags: + - Each grid level gets its own enter_tag (entry_grid_XXXX) + - This allows Freqtrade to create multiple orders per candle - Buy at predefined grid levels: 1500, 1550, 1600, ..., 4500 (step 50) - - Also buy AT CURRENT PRICE and below it - - When price is at or below a grid level, produce buy signal """ dataframe['enter_long'] = False + dataframe['enter_tag'] = "" if len(dataframe) == 0: return dataframe @@ -59,7 +61,6 @@ class StaticGrid(IStrategy): grid_levels = [LOWER + i * STEP for i in range(int((UPPER - LOWER) / STEP) + 1)] # IMPORTANT: Add current price as a grid level too (rounded to nearest STEP) - # This ensures we can buy immediately at current price current_grid_level = round(current_price / STEP) * STEP if current_grid_level not in grid_levels and LOWER <= current_grid_level <= UPPER: grid_levels.append(current_grid_level) @@ -67,13 +68,15 @@ class StaticGrid(IStrategy): grid_levels.sort() entry_count = 0 + grid_tags = [] # Collect all grid levels that should trigger entry # For each grid level, check if price is at or below it for grid_price in grid_levels: # Buy if current low is at or below this grid level (with 0.5% tolerance) if current_low <= grid_price * 1.005: - dataframe['enter_long'] = True entry_count += 1 + tag = f"grid_{int(grid_price)}" + grid_tags.append(tag) if entry_count <= 5: # Only print first 5 for brevity print(f"[StaticGrid] Entry at grid {grid_price:.0f}", file=sys.stderr, flush=True) @@ -82,6 +85,12 @@ class StaticGrid(IStrategy): print(f"[StaticGrid] Total entry signals: {entry_count}", file=sys.stderr, flush=True) + # Set enter_long = True for the last row (current candle) + if entry_count > 0: + dataframe.loc[dataframe.index[-1], 'enter_long'] = True + # Use the grid tags separated by comma + dataframe.loc[dataframe.index[-1], 'enter_tag'] = ','.join(grid_tags) + return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: @@ -105,5 +114,30 @@ class StaticGrid(IStrategy): return dataframe - def custom_stake_amount(self, **kwargs) -> float: - return self.STAKE + def adjust_trade_position(self, trade, current_rate: float, + current_profit: float, min_stake: float, + max_stake: float, **kwargs) -> Optional[float]: + """ + Network Grid Position Adjustment (DCA - Dollar Cost Averaging): + 每当价格跌到新的网格点时,自动加仓 + """ + LOWER = 1500.0 + UPPER = 4500.0 + STEP = 50.0 + + # Only add position if price drops to a new grid level + grid_level = round(current_rate / STEP) * STEP + + # Calculate how many positions we've already opened + open_positions = trade.nr_of_successful_entries + + # Maximum positions per pair = (UPPER - LOWER) / STEP + max_positions = int((UPPER - LOWER) / STEP) + 1 + + if open_positions < max_positions and LOWER <= grid_level <= UPPER: + # Add position at each grid level + print(f"[StaticGrid] Adding position at grid level {grid_level:.0f}, current rate {current_rate:.2f}", + file=sys.stderr, flush=True) + return self.STAKE + + return None