One-Minute Oscillator Scalping with a Higher-Timeframe Trend Filter
Summary
ReinforcedSmoothScalp is a one-minute long-only scalping strategy that seeks frequent entries and small gains. It resamples price to a five-minute interval and uses a 50-period simple moving average there as a broad trend filter. On the trading timeframe, candidate entries combine a fast stochastic crossover with configurable thresholds for indicators such as money flow and ADX, while requiring positive volume and price above the resampled average. Exits combine an open-price condition relative to a short EMA of highs with configurable oscillator thresholds. The framework specifies a 2% minimum profit target and a 10% stop loss.
The accompanying description recommends maintaining at least 60 simultaneous trades to absorb unavoidable losses, but provides no supporting performance evidence. Frequent trading and small targets make costs and portfolio exposure consequential; the listed stop is wide relative to the target. The code defines several indicator and exit parameters, while its explanatory prose does not establish that the recommended trade count is feasible or suitable across markets.
Key ideas
- The strategy seeks frequent one-minute long entries for small per-trade gains.
- A five-minute moving average filters entries to periods when price is above the average.
- A fast stochastic crossover and configurable oscillator thresholds shape entry and exit signals.
- The framework specifies a 2% profit target and a 10% stop loss.
- The document recommends many simultaneous trades but supplies no evidence supporting that recommendation.
Tags
Full text
# ReinforcedSmoothScalp
# ReinforcedSmoothScalp
this strategy is based around the idea of generating a lot of potential buys and make tiny profits on each trade
we recommend to have at least 60 parallel trades at any time to cover non-avoidable losses
## Source (GPL-3.0)
```python
# --- Do not remove these libs ---
from functools import reduce
from freqtrade.strategy import IStrategy
from freqtrade.strategy import timeframe_to_minutes
from freqtrade.strategy import BooleanParameter, IntParameter
from pandas import DataFrame
from technical.util import resample_to_interval, resampled_merge
import numpy # noqa
# --------------------------------
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
class ReinforcedSmoothScalp(IStrategy):
"""
this strategy is based around the idea of generating a lot of potential buys and make tiny profits on each trade
we recommend to have at least 60 parallel trades at any time to cover non-avoidable losses
"""
INTERFACE_VERSION: int = 3
# Minimal ROI designed for the strategy.
# This attribute will be overridden if the config file contains "minimal_roi"
minimal_roi = {
"0": 0.02
}
# Optimal stoploss designed for the strategy
# This attribute will be overridden if the config file contains "stoploss"
# should not be below 3% loss
stoploss = -0.1
# Optimal timeframe for the strategy
# the shorter the better
timeframe = '1m'
# resample factor to establish our general trend. Basically don't buy if a trend is not given
resample_factor = 5
buy_adx = IntParameter(20, 50, default=32, space='buy')
buy_fastd = IntParameter(15, 45, default=30, space='buy')
buy_fastk = IntParameter(15, 45, default=26, space='buy')
buy_mfi = IntParameter(10, 25, default=22, space='buy')
buy_adx_enabled = BooleanParameter(default=True, space='buy')
buy_fastd_enabled = BooleanParameter(default=True, space='buy')
buy_fastk_enabled = BooleanParameter(default=False, space='buy')
buy_mfi_enabled = BooleanParameter(default=True, space='buy')
sell_adx = IntParameter(50, 100, default=53, space='sell')
sell_cci = IntParameter(100, 200, default=183, space='sell')
sell_fastd = IntParameter(50, 100, default=79, space='sell')
sell_fastk = IntParameter(50, 100, default=70, space='sell')
sell_mfi = IntParameter(75, 100, default=92, space='sell')
sell_adx_enabled = BooleanParameter(default=False, space='sell')
sell_cci_enabled = BooleanParameter(default=True, space='sell')
sell_fastd_enabled = BooleanParameter(default=True, space='sell')
sell_fastk_enabled = BooleanParameter(default=True, space='sell')
sell_mfi_enabled = BooleanParameter(default=False, space='sell')
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
tf_res = timeframe_to_minutes(self.timeframe) * 5
df_res = resample_to_interval(dataframe, tf_res)
df_res['sma'] = ta.SMA(df_res, 50, price='close')
dataframe = resampled_merge(dataframe, df_res, fill_na=True)
dataframe['resample_sma'] = dataframe[f'resample_{tf_res}_sma']
dataframe['ema_high'] = ta.EMA(dataframe, timeperiod=5, price='high')
dataframe['ema_close'] = ta.EMA(dataframe, timeperiod=5, price='close')
dataframe['ema_low'] = ta.EMA(dataframe, timeperiod=5, price='low')
stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0)
dataframe['fastd'] = stoch_fast['fastd']
dataframe['fastk'] = stoch_fast['fastk']
dataframe['adx'] = ta.ADX(dataframe)
dataframe['cci'] = ta.CCI(dataframe, timeperiod=20)
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe['mfi'] = ta.MFI(dataframe)
# required for graphing
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
dataframe['bb_upperband'] = bollinger['upper']
dataframe['bb_middleband'] = bollinger['mid']
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
if self.buy_mfi_enabled.value:
conditions.append(dataframe['mfi'] < self.buy_mfi.value)
if self.buy_fastd_enabled.value:
conditions.append(dataframe['fastd'] < self.buy_fastd.value)
if self.buy_fastk_enabled.value:
conditions.append(dataframe['fastk'] < self.buy_fastk.value)
if self.buy_adx_enabled.value:
conditions.append(dataframe['adx'] > self.buy_adx.value)
# Some static conditions which always apply
conditions.append(qtpylib.crossed_above(dataframe['fastk'], dataframe['fastd']))
conditions.append(dataframe['resample_sma'] < dataframe['close'])
# Check that volume is not 0
conditions.append(dataframe['volume'] > 0)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'enter_long'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
# Some static conditions which always apply
conditions.append(dataframe['open'] > dataframe['ema_high'])
if self.sell_mfi_enabled.value:
conditions.append(dataframe['mfi'] > self.sell_mfi.value)
if self.sell_fastd_enabled.value:
conditions.append(dataframe['fastd'] > self.sell_fastd.value)
if self.sell_fastk_enabled.value:
conditions.append(dataframe['fastk'] > self.sell_fastk.value)
if self.sell_adx_enabled.value:
conditions.append(dataframe['adx'] < self.sell_adx.value)
if self.sell_cci_enabled.value:
conditions.append(dataframe['cci'] > self.sell_cci.value)
# Check that volume is not 0
conditions.append(dataframe['volume'] > 0)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'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.