BtcRsi2Guarded.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. from datetime import datetime
  2. import pandas as pd
  3. from freqtrade.persistence import Trade
  4. from freqtrade.strategy import IStrategy
  5. class BtcRsi2Guarded(IStrategy):
  6. INTERFACE_VERSION = 3
  7. timeframe = "15m"
  8. can_short = False
  9. startup_candle_count = 240
  10. process_only_new_candles = True
  11. minimal_roi = {"0": 100.0}
  12. stoploss = -0.024
  13. use_exit_signal = True
  14. exit_profit_only = False
  15. ignore_roi_if_entry_signal = False
  16. trend_sma = 240
  17. rsi_length = 2
  18. rsi_threshold = 2.0
  19. exit_rsi = 55.0
  20. max_hold_bars = 48
  21. leverage_value = 3.0
  22. def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
  23. dataframe["trend"] = dataframe["close"].rolling(self.trend_sma).mean()
  24. dataframe["rsi2"] = self._rsi(dataframe["close"], self.rsi_length)
  25. return dataframe
  26. def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
  27. dataframe.loc[
  28. (dataframe["close"] > dataframe["trend"]) & (dataframe["rsi2"] <= self.rsi_threshold),
  29. ["enter_long", "enter_tag"],
  30. ] = (1, "rsi2_guarded")
  31. return dataframe
  32. def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
  33. dataframe.loc[dataframe["rsi2"] >= self.exit_rsi, ["exit_long", "exit_tag"]] = (1, "rsi_exit")
  34. return dataframe
  35. def custom_exit(
  36. self,
  37. pair: str,
  38. trade: Trade,
  39. current_time: datetime,
  40. current_rate: float,
  41. current_profit: float,
  42. **kwargs,
  43. ) -> str | None:
  44. held_bars = int((current_time - trade.open_date_utc).total_seconds() // (15 * 60))
  45. if held_bars >= self.max_hold_bars:
  46. return "max_hold"
  47. return None
  48. def leverage(
  49. self,
  50. pair: str,
  51. current_time: datetime,
  52. current_rate: float,
  53. proposed_leverage: float,
  54. max_leverage: float,
  55. entry_tag: str | None,
  56. side: str,
  57. **kwargs,
  58. ) -> float:
  59. return min(self.leverage_value, max_leverage)
  60. @staticmethod
  61. def _rsi(close: pd.Series, length: int) -> pd.Series:
  62. deltas = close.diff()
  63. gains = deltas.clip(lower=0.0)
  64. losses = -deltas.clip(upper=0.0)
  65. values = [float("nan")] * len(close)
  66. if len(close) <= length:
  67. return pd.Series(values, index=close.index)
  68. average_gain = float(gains.iloc[1 : length + 1].mean())
  69. average_loss = float(losses.iloc[1 : length + 1].mean())
  70. for index in range(length, len(close)):
  71. if index > length:
  72. average_gain = ((average_gain * (length - 1)) + float(gains.iloc[index])) / length
  73. average_loss = ((average_loss * (length - 1)) + float(losses.iloc[index])) / length
  74. if pd.isna(average_gain) or pd.isna(average_loss):
  75. continue
  76. if average_loss == 0.0:
  77. values[index] = 100.0 if average_gain > 0.0 else 50.0
  78. continue
  79. relative_strength = average_gain / average_loss
  80. values[index] = 100.0 - (100.0 / (1.0 + relative_strength))
  81. return pd.Series(values, index=close.index)