EthNextgenMicroLeverageUnitsShifted.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. from __future__ import annotations
  2. import os
  3. from datetime import datetime
  4. from pathlib import Path
  5. import pandas as pd
  6. from freqtrade.strategy import IStrategy
  7. class EthNextgenMicroLeverageUnitsShifted(IStrategy):
  8. INTERFACE_VERSION = 3
  9. timeframe = "15m"
  10. can_short = True
  11. startup_candle_count = 0
  12. process_only_new_candles = True
  13. minimal_roi = {"0": 100.0}
  14. stoploss = -0.99
  15. use_exit_signal = True
  16. exit_profit_only = False
  17. ignore_roi_if_entry_signal = False
  18. def __init__(self, config: dict) -> None:
  19. super().__init__(config)
  20. self._stake_units: dict[tuple[pd.Timestamp, str], float] = {}
  21. def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
  22. trades_path = Path(
  23. os.environ.get(
  24. "ETH_NEXTGEN_MICRO_LEVERAGE_UNITS",
  25. "reports/eth-exploration/eth-nextgen-micro-leverage-units-trades.csv",
  26. )
  27. )
  28. trades = pd.read_csv(trades_path)
  29. trades["entry_date"] = pd.to_datetime(trades["entry_time"], utc=True) - pd.Timedelta(minutes=15)
  30. trades["exit_date_ts"] = pd.to_datetime(trades["exit_time"], utc=True) - pd.Timedelta(minutes=15)
  31. self._stake_units = {
  32. (row.entry_date, str(row.side)): float(row.position_unit)
  33. for row in trades.itertuples(index=False)
  34. }
  35. entries = trades[["entry_date", "side", "position_unit"]].rename(columns={"entry_date": "date"})
  36. exits = trades[["exit_date_ts"]].drop_duplicates().rename(columns={"exit_date_ts": "date"})
  37. entries["enter_long_unit"] = 0.0
  38. entries["enter_short_unit"] = 0.0
  39. entries.loc[entries["side"] == "long", "enter_long_unit"] = entries["position_unit"]
  40. entries.loc[entries["side"] == "short", "enter_short_unit"] = entries["position_unit"]
  41. entries = entries.groupby("date", as_index=False).agg(
  42. enter_long_unit=("enter_long_unit", "max"),
  43. enter_short_unit=("enter_short_unit", "max"),
  44. )
  45. exits["exit_signal"] = 1
  46. merged = dataframe.merge(entries, on="date", how="left").merge(exits, on="date", how="left")
  47. merged[["enter_long_unit", "enter_short_unit", "exit_signal"]] = merged[
  48. ["enter_long_unit", "enter_short_unit", "exit_signal"]
  49. ].fillna(0.0)
  50. return merged
  51. def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
  52. dataframe.loc[dataframe["enter_long_unit"] > 0.0, ["enter_long", "enter_tag"]] = (1, "shifted_unit_long")
  53. dataframe.loc[dataframe["enter_short_unit"] > 0.0, ["enter_short", "enter_tag"]] = (1, "shifted_unit_short")
  54. return dataframe
  55. def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
  56. dataframe.loc[dataframe["exit_signal"] > 0.0, ["exit_long", "exit_tag"]] = (1, "shifted_unit_exit")
  57. dataframe.loc[dataframe["exit_signal"] > 0.0, ["exit_short", "exit_tag"]] = (1, "shifted_unit_exit")
  58. return dataframe
  59. def custom_stake_amount(
  60. self,
  61. pair: str,
  62. current_time: datetime,
  63. current_rate: float,
  64. proposed_stake: float,
  65. min_stake: float | None,
  66. max_stake: float,
  67. leverage: float,
  68. entry_tag: str | None,
  69. side: str,
  70. **kwargs,
  71. ) -> float:
  72. timestamp = pd.Timestamp(current_time)
  73. timestamp = timestamp.tz_localize("UTC") if timestamp.tzinfo is None else timestamp.tz_convert("UTC")
  74. unit = self._stake_units.get((timestamp, side), 1.0)
  75. stake = max_stake * unit
  76. if min_stake is not None:
  77. stake = max(stake, min_stake)
  78. return min(stake, max_stake)
  79. def leverage(
  80. self,
  81. pair: str,
  82. current_time: datetime,
  83. current_rate: float,
  84. proposed_leverage: float,
  85. max_leverage: float,
  86. entry_tag: str | None,
  87. side: str,
  88. **kwargs,
  89. ) -> float:
  90. return min(3.0, max_leverage)