Skip to content
All library documents

Moving-Average Ratio Entries and Exits with Hyperparameter Tuning

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

Summary

This four-hour long-only strategy generates entries and exits from ratios among three simple moving averages. For entry, the ratio of a short “mojo” average to a faster average, and the faster average to a slower average, must each fall within configured bounds. Exit logic uses separate moving-average periods and bounds, comparing the faster average with the mojo average and the slower average with the faster one. The strategy also specifies a staged return-on-investment schedule and a fixed stop loss.

The source is presented as requiring hyperparameter optimization with a Sharpe-based loss across the strategy’s parameter spaces. However, it provides no asset universe, test period, or performance evidence, and the listed exit defaults and bounds appear inconsistent with the stated parameter ranges. Optimization can overfit, so the shown settings should not be treated as validated results. Reproduction would require resolving the parameter discrepancies and evaluating the strategy out of sample with trading costs.

Key ideas

  • Entries depend on two moving-average ratios falling within configurable bounds.
  • Exits use separate moving-average periods and ratio thresholds from the entry rules.
  • The strategy specifies a four-hour timeframe, staged profit targets, and a fixed stop loss.
  • The source calls for hyperparameter optimization using a Sharpe-based objective.
  • The parameter defaults include apparent inconsistencies, and no performance results are supplied.

Tags

Full text
# mabStra


# mabStra









## Source (GPL-3.0)

```python
# Author: @Mablue (Masoud Azizi)
# github: https://github.com/mablue/
# IMPORTANT: DO NOT USE IT WITHOUT HYPEROPT:
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces all --strategy mabStra --config config.json -e 100

# --- Do not remove these libs ---
from freqtrade.strategy import IntParameter, DecimalParameter, IStrategy
from pandas import DataFrame
# --------------------------------

# Add your lib to import here
import talib.abstract as ta


class mabStra(IStrategy):

    INTERFACE_VERSION: int = 3
    # #################### RESULTS PASTE PLACE ####################
    # ROI table:
    minimal_roi = {
        "0": 0.598,
        "644": 0.166,
        "3269": 0.115,
        "7289": 0
    }

    # Stoploss:
    stoploss = -0.128
    # Buy hypers
    timeframe = '4h'

    # #################### END OF RESULT PLACE ####################

    # buy params
    buy_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='buy')
    buy_fast_ma_timeframe = IntParameter(2, 100, default=14, space='buy')
    buy_slow_ma_timeframe = IntParameter(2, 100, default=28, space='buy')
    buy_div_max = DecimalParameter(
        0, 2, decimals=4, default=2.25446, space='buy')
    buy_div_min = DecimalParameter(
        0, 2, decimals=4, default=0.29497, space='buy')
    # sell params
    sell_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='sell')
    sell_fast_ma_timeframe = IntParameter(2, 100, default=14, space='sell')
    sell_slow_ma_timeframe = IntParameter(2, 100, default=28, space='sell')
    sell_div_max = DecimalParameter(
        0, 2, decimals=4, default=1.54593, space='sell')
    sell_div_min = DecimalParameter(
        0, 2, decimals=4, default=2.81436, space='sell')

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # SMA - ex Moving Average
        dataframe['buy-mojoMA'] = ta.SMA(dataframe,
                                         timeperiod=self.buy_mojo_ma_timeframe.value)
        dataframe['buy-fastMA'] = ta.SMA(dataframe,
                                         timeperiod=self.buy_fast_ma_timeframe.value)
        dataframe['buy-slowMA'] = ta.SMA(dataframe,
                                         timeperiod=self.buy_slow_ma_timeframe.value)
        dataframe['sell-mojoMA'] = ta.SMA(dataframe,
                                          timeperiod=self.sell_mojo_ma_timeframe.value)
        dataframe['sell-fastMA'] = ta.SMA(dataframe,
                                          timeperiod=self.sell_fast_ma_timeframe.value)
        dataframe['sell-slowMA'] = ta.SMA(dataframe,
                                          timeperiod=self.sell_slow_ma_timeframe.value)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        dataframe.loc[
            (
                (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA'])
                    > self.buy_div_min.value) &
                (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA'])
                    < self.buy_div_max.value) &
                (dataframe['buy-fastMA'].div(dataframe['buy-slowMA'])
                    > self.buy_div_min.value) &
                (dataframe['buy-fastMA'].div(dataframe['buy-slowMA'])
                    < self.buy_div_max.value)
            ),
            'enter_long'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA'])
                    > self.sell_div_min.value) &
                (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA'])
                    < self.sell_div_max.value) &
                (dataframe['sell-slowMA'].div(dataframe['sell-fastMA'])
                    > self.sell_div_min.value) &
                (dataframe['sell-slowMA'].div(dataframe['sell-fastMA'])
                    < self.sell_div_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.