Timeframe
5m
Direction
Long Only
Stoploss
-10.0%
Trailing Stop
No
ROI
0m: 4.0%, 30m: 2.0%, 60m: 1.0%
Interface Version
3
Startup Candles
200
Indicators
0
freqtrade/freqtrade-strategies
author@: lenik
# user_data/strategies/PolusStrategy.py
import numpy as np
import pandas as pd
from pandas import DataFrame
from freqtrade.strategy.interface import IStrategy
# Убедитесь, что путь к индикатору правильный
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
from indicators.polus_x import PolusX
class PolusStrategy(IStrategy):
"""
Стратегия на основе индикатора PolusX
"""
# Базовые настройки стратегии
INTERFACE_VERSION = 3
# Настройки временного интервала
timeframe = '5m'
process_only_new_candles = True
startup_candle_count = 200
# Настройки ROI и стоп-лосса
minimal_roi = {
"60": 0.01,
"30": 0.02,
"0": 0.04
}
stoploss = -0.10
trailing_stop = False
# Настройки сигналов выхода
use_exit_signal = True
exit_profit_only = False
ignore_roi_if_entry_signal = False
# Конфигурация графика
plot_config = {
'main_plot': {
'polus_high1': {'color': 'green'},
'polus_min1': {'color': 'red'},
'polus_max2': {'color': 'aqua'},
'polus_min2': {'color': 'magenta'},
'polus_max3': {'color': 'steelblue'},
'polus_min3': {'color': 'orangered'},
'polus_cl': {'color': 'gold'},
}
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Добавляет индикаторы PolusX к dataframe
"""
if dataframe.empty:
return dataframe
# Проверяем наличие необходимых колонок
required_columns = ['open', 'high', 'low', 'close', 'volume']
for col in required_columns:
if col not in dataframe.columns:
print(f"Warning: Missing column {col}")
return dataframe
try:
# Создаём экземпляр индикатора
polus = PolusX(use_tick_volume=False, show_lines=True, ind1=True, ind2=True, ind3=True)
# Вычисляем индикаторы
high1, min1 = polus._calc_ind1(dataframe)
max2, min2 = polus._calc_ind2(dataframe)
max3, min3, cl = polus._calc_ind3(dataframe)
# Добавляем индикаторы в dataframe
dataframe['polus_high1'] = high1
dataframe['polus_min1'] = min1
dataframe['polus_max2'] = max2
dataframe['polus_min2'] = min2
dataframe['polus_max3'] = max3
dataframe['polus_min3'] = min3
dataframe['polus_cl'] = cl
# Добавляем сдвинутые значения для сравнения
dataframe['close_prev'] = dataframe['close'].shift(1)
dataframe['ph1_prev'] = dataframe['polus_high1'].shift(1)
dataframe['pm1_prev'] = dataframe['polus_min1'].shift(1)
# Заполняем NaN значения для корректной работы
for col in ['polus_high1', 'polus_min1', 'polus_max2', 'polus_min2',
'polus_max3', 'polus_min3', 'polus_cl']:
dataframe[col] = dataframe[col].fillna(method='ffill')
except Exception as e:
print(f"Error in populate_indicators: {e}")
# В случае ошибки возвращаем dataframe с NaN значениями
for col in ['polus_high1', 'polus_min1', 'polus_max2', 'polus_min2',
'polus_max3', 'polus_min3', 'polus_cl', 'close_prev',
'ph1_prev', 'pm1_prev']:
dataframe[col] = np.nan
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Определяет сигналы на вход в позицию
"""
# Инициализируем колонку входа
dataframe.loc[:, 'enter_long'] = False
# Проверяем наличие необходимых колонок
required_cols = ['close', 'polus_high1', 'close_prev', 'ph1_prev']
if not all(col in dataframe.columns for col in required_cols):
return dataframe
try:
# Условие входа: цена закрытия пересекает вверх polus_high1
cond = (
(dataframe['close'] > dataframe['polus_high1']) &
(dataframe['close_prev'] <= dataframe['ph1_prev']) &
(dataframe['volume'] > 0) & # Убеждаемся что есть объём
(~dataframe['polus_high1'].isna()) & # Индикатор не NaN
(~dataframe['ph1_prev'].isna()) # Предыдущее значение не NaN
)
dataframe.loc[cond, 'enter_long'] = True
dataframe.loc[cond, 'enter_tag'] = 'cross_ph1_up'
except Exception as e:
print(f"Error in populate_entry_trend: {e}")
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Определяет сигналы на выход из позиции
Выход когда close пересекает ВНИЗ polus_min1 (пробой «нижнего» уровня).
"""
# Инициализируем колонку выхода
dataframe.loc[:, 'exit_long'] = False
# Проверяем наличие необходимых колонок
required_cols = ['close', 'polus_min1', 'close_prev', 'pm1_prev']
if not all(col in dataframe.columns for col in required_cols):
return dataframe
try:
# Условие выхода: цена закрытия пересекает вниз polus_min1
cond_cross_down = (
(dataframe['close'] < dataframe['polus_min1']) &
(dataframe['close_prev'] >= dataframe['pm1_prev']) &
(dataframe['volume'] > 0) & # Убеждаемся что есть объём
(~dataframe['polus_min1'].isna()) & # Индикатор не NaN
(~dataframe['pm1_prev'].isna()) # Предыдущее значение не NaN
)
dataframe.loc[cond_cross_down, 'exit_long'] = True
dataframe.loc[cond_cross_down, 'exit_tag'] = 'cross_pm1_down'
except Exception as e:
print(f"Error in populate_exit_trend: {e}")
return dataframe