Skip to content
All library documents

Hourly Entry and Exit Windows Optimized with Hyperopt

Article Strategy library · Author: @Mablue (Masoud Azizi)

Summary

This strategy bases trading decisions solely on the hour of the candle. It is intended for hourly data: configurable start and end hours define when to enter long and when to exit. It uses no price, volume, or technical indicator conditions. The accompanying code recommends optimizing these hour windows with Freqtrade’s hyperparameter search and also specifies ROI targets and a stop loss.

The document reports sample optimization outcomes for several crypto pairs over 100-day periods, including trade counts, win, draw, and loss counts, average and median returns, total returns, and trade duration. These are examples from parameter searches, not evidence of robust out-of-sample performance. Results differ substantially among pairs and settings, and the selected entry and exit windows may fit historical hourly patterns. The strategy also requires careful attention to the time zone used by candle timestamps, while its hour-window logic and exits should be validated on the intended market and data feed.

Key ideas

  • Entry and exit signals are determined by whether the candle hour falls within configured ranges.
  • The strategy is designed to run on one-hour candles and requires no indicator calculations.
  • Hyperparameter optimization is used to search hourly windows and risk settings.
  • Reported sample outcomes vary across pairs and settings and do not establish out-of-sample reliability.
  • Timestamp time zones and historical fitting can affect whether the selected hour windows generalize.

Tags

Full text
# HourBasedStrategy


# HourBasedStrategy









## Source (GPL-3.0)

```python
# Hour Strategy
# In this strategy we try to find the best hours to buy and sell in a day.(in hourly timeframe)
# Because of that you should just use 1h timeframe on this strategy.
# Author: @Mablue (Masoud Azizi)
# github: https://github.com/mablue/
# Requires hyperopt before running.
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy HourBasedStrategy -e 200


from freqtrade.strategy import IntParameter, IStrategy
from pandas import DataFrame

# --------------------------------
# Add your lib to import here
# No need to These imports. just for who want to add more conditions:
# import talib.abstract as ta
# import freqtrade.vendor.qtpylib.indicators as qtpylib


class HourBasedStrategy(IStrategy):
    # SHIB/USDT, 1000$x1:100days
    # 158/1000:     51 trades. 29/19/3 Wins/Draws/Losses. Avg profit   4.02%. Median profit   2.48%. Total profit  4867.53438466 USDT ( 486.75%). Avg duration 1 day, 19:38:00 min. Objective: -4.17276
    # buy_params = {"buy_hour_max": 18,"buy_hour_min": 7,}
    # sell_params = {"sell_hour_max": 9,"sell_hour_min": 21,}
    # minimal_roi = {"0": 0.18,"171": 0.155,"315": 0.075,"1035": 0}
    # stoploss = -0.292

    # SHIB/USDT, 1000$x1:100days
    # 36/1000:    113 trades. 55/14/44 Wins/Draws/Losses. Avg profit   2.06%. Median profit   0.00%. Total profit  5126.14785426 USDT ( 512.61%). Avg duration 16:48:00 min. Objective: -4.57837
    # buy_params = {"buy_hour_max": 21,"buy_hour_min": 6,}
    # sell_params = {"sell_hour_max": 6,"sell_hour_min": 4,}
    # minimal_roi = {"0": 0.247,"386": 0.186,"866": 0.052,"1119": 0}
    # stoploss = -0.302

    # SAND/USDT, 1000$x1:100days
    # 72/1000:    158 trades. 67/13/78 Wins/Draws/Losses. Avg profit   1.37%. Median profit   0.00%. Total profit  4274.73622346 USDT ( 427.47%). Avg duration 13:50:00 min. Objective: -4.87331
    # buy_params = {"buy_hour_max": 23,"buy_hour_min": 4,}
    # sell_params = {"sell_hour_max": 23,"sell_hour_min": 3,}
    # minimal_roi = {"0": 0.482,"266": 0.191,"474": 0.09,"1759": 0}
    # stoploss = -0.05

    # KDA/USDT, 1000$x1:100days
    # 7/1000:     65 trades. 40/23/2 Wins/Draws/Losses. Avg profit   6.42%. Median profit   7.59%. Total profit  41120.00939125 USDT ( 4112.00%). Avg duration 1 day, 9:40:00 min. Objective: -8.46089
    # buy_params = {"buy_hour_max": 22,"buy_hour_min": 9,}
    # sell_params = {"sell_hour_max": 1,"sell_hour_min": 7,}
    # minimal_roi = {"0": 0.517,"398": 0.206,"1003": 0.076,"1580": 0}
    # stoploss = -0.338

    # {KDA/USDT, BTC/USDT, DOGE/USDT, SAND/USDT, ETH/USDT, SOL/USDT}, 1000$x1:100days, ShuffleFilter42
    # 56/1000:     63 trades. 41/19/3 Wins/Draws/Losses. Avg profit   4.60%. Median profit   8.89%. Total profit  11596.50333022 USDT ( 1159.65%). Avg duration 1 day, 14:46:00 min. Objective: -5.76694

    INTERFACE_VERSION: int = 3
    # Buy hyperspace params:
    buy_params = {
        "buy_hour_max": 24,
        "buy_hour_min": 4,
    }

    # Sell hyperspace params:
    sell_params = {
        "sell_hour_max": 21,
        "sell_hour_min": 22,
    }

    # ROI table:
    minimal_roi = {
        "0": 0.528,
        "169": 0.113,
        "528": 0.089,
        "1837": 0
    }

    # Stoploss:
    stoploss = -0.10

    # Optimal timeframe
    timeframe = '1h'

    buy_hour_min = IntParameter(0, 24, default=1, space='buy')
    buy_hour_max = IntParameter(0, 24, default=0, space='buy')

    sell_hour_min = IntParameter(0, 24, default=1, space='sell')
    sell_hour_max = IntParameter(0, 24, default=0, space='sell')

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['hour'] = dataframe['date'].dt.hour
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['hour'].between(self.buy_hour_min.value, self.buy_hour_max.value))
            ),
            'enter_long'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['hour'].between(self.sell_hour_min.value, self.sell_hour_max.value))
            ),
            'exit_long'] = 1
        return dataframe

```

Shown in full with attribution under the source's licence. Licence: GPL-3.0

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.