Freqtrade strategy using only OBV and OBV_EMA (hyperoptable period). Long: OBV crosses above its EMA. Short: OBV crosses below its EMA (can_short = True).
Timeframe
5m
Direction
Long & Short
Stoploss
-10.0%
Trailing Stop
No
ROI
0m: 2.0%
Interface Version
3
Startup Candles
N/A
Indicators
2
freqtrade/freqtrade-strategies
import numpy as np
import pandas as pd
from pandas import DataFrame
from freqtrade.strategy import IStrategy, IntParameter
import talib.abstract as ta
class OBVEMAStrategy(IStrategy):
"""
Freqtrade strategy using only OBV and OBV_EMA (hyperoptable period).
Long: OBV crosses above its EMA.
Short: OBV crosses below its EMA (can_short = True).
"""
INTERFACE_VERSION = 3
can_short: bool = True
timeframe = "5m"
minimal_roi = {"0": 0.02}
stoploss = -0.10
trailing_stop = False
process_only_new_candles = True
startup_candle_count: int = 50
# Hyperoptable parameter for OBV_EMA period
obv_ema_period = IntParameter(5, 50, default=20, space="buy", optimize=True, load=True)
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# On-Balance Volume (OBV)
dataframe["obv"] = ta.OBV(dataframe)
# OBV EMA (hyperoptable period)
dataframe["obv_ema"] = dataframe["obv"].ewm(span=self.obv_ema_period.value, adjust=False).mean()
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Long: OBV crosses above its EMA
dataframe.loc[
(dataframe["obv"] > dataframe["obv_ema"]) &
(dataframe["obv"].shift(1) <= dataframe["obv_ema"].shift(1)) &
(dataframe["volume"] > 0),
"enter_long"
] = 1
# Short: OBV crosses below its EMA (if shorts enabled)
dataframe.loc[
(dataframe["obv"] < dataframe["obv_ema"]) &
(dataframe["obv"].shift(1) >= dataframe["obv_ema"].shift(1)) &
(dataframe["volume"] > 0),
"enter_short"
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Exit long: OBV crosses below its EMA
dataframe.loc[
(dataframe["obv"] < dataframe["obv_ema"]) &
(dataframe["obv"].shift(1) >= dataframe["obv_ema"].shift(1)) &
(dataframe["volume"] > 0),
"exit_long"
] = 1
# Exit short: OBV crosses above its EMA
dataframe.loc[
(dataframe["obv"] > dataframe["obv_ema"]) &
(dataframe["obv"].shift(1) <= dataframe["obv_ema"].shift(1)) &
(dataframe["volume"] > 0),
"exit_short"
] = 1
return dataframe