Signal-only strategy with proper stoploss handling.
Timeframe
N/A
Direction
Long Only
Stoploss
-15.0%
Trailing Stop
No
ROI
0m: 5.0%, 60m: 2.0%, 120m: 1.0%, 180m: 0.5%
Interface Version
N/A
Startup Candles
N/A
Indicators
0
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
"""
Signal-only strategy with corrected stoploss handling.
"""
from datetime import datetime
from typing import Dict, List, Optional, Tuple
import numpy as np
import talib.abstract as ta
from pandas import DataFrame
from freqtrade.enums import ExitType, SignalDirection, TradeDirection
from freqtrade.exceptions import OperationalException
from freqtrade.persistence import Trade
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter, CategoricalParameter
class SignalOnlyStrategy(IStrategy):
"""
Signal-only strategy with proper stoploss handling.
"""
# ROI table:
minimal_roi = {
"0": 0.05, # 5% if held for less than 1 hour
"60": 0.02, # 2% if held for 1 hour or more
"120": 0.01, # 1% if held for 2 hours or more
"180": 0.005, # 0.5% if held for 3 hours or more
"240": 0, # Stop loss if held for 4 hours or more
}
# Stoploss
stoploss = -0.15 # 15% stoploss
# Trailing stop
trailing_stop = False
trailing_stop_positive = 0.001 # 0.1%
trailing_stop_positive_offset = 0.002 # 0.2%
trailing_only_offset_as_percent = False
# Order types
order_types = {
'entry': 'market',
'exit': 'market',
'stoploss': 'market',
'stoploss_on_exchange': True,
'stoploss_on_exchange_interval': 60,
}
# Leverage
leverage_option = CategoricalParameter([1, 2, 5, 10, 25], default=1, space='buy', optimize=False)
short_leverage_option = CategoricalParameter([1, 2, 5, 10, 25], default=1, space='sell', optimize=False)
# Custom parameters
use_signal_stoploss = True
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# No indicators needed for signal-only strategy
dataframe['enter_long'] = 0
dataframe['enter_short'] = 0
dataframe['exit_long'] = 0
dataframe['exit_short'] = 0
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[:, 'enter_long'] = 0
dataframe.loc[:, 'enter_short'] = 0
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[:, "exit_long"] = 0
dataframe.loc[:, "exit_short"] = 0
return dataframe
def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
"""
Strictly use the stoploss price set during entry.
No trailing, no adjustments.
"""
# Use stoploss from signal
signal_sl = trade.get_custom_data("signal_sl")
if signal_sl is not None:
sl_price = float(signal_sl)
if not trade.is_short:
if sl_price < current_rate:
return (sl_price / current_rate) - 1
else:
if sl_price > current_rate:
return 1 - (sl_price / current_rate)
# Fallback to strategy stoploss if signal data is missing
return self.stoploss
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
current_profit: float, **kwargs) -> str | bool | None:
# Take profit from signal
signal_tp = trade.get_custom_data("signal_tp")
if signal_tp is not None:
tp_price = float(signal_tp)
if not trade.is_short:
if current_rate >= tp_price:
return "signal_tp"
else:
if current_rate <= tp_price:
return "signal_tp"
return None
def leverages(self) -> Tuple[List[Optional[int]], List[Optional[int]]]:
"""Return leverage settings for long and short positions."""
return [self.leverage_option.value], [self.short_leverage_option.value]
def get_signal_direction(self, pair: str, trade: Trade) -> Optional[SignalDirection]:
"""Return signal direction based on trade properties."""
try:
if trade.is_short:
return SignalDirection.SHORT
return SignalDirection.LONG
except Exception:
return None
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Signal-only strategy - no entry indicators
dataframe.loc[:, 'enter_long'] = 0
dataframe.loc[:, 'enter_short'] = 0
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Signal-only strategy - no exit indicators
dataframe.loc[:, "exit_long"] = 0
dataframe.loc[:, "exit_short"] = 0
return dataframe