FSD – Custom indicators part 1

DISCLAIMER
The codes in this post is just for educational purpose, and not to be used on live trading

There are times you might want to use an indicator that might not have been implemented by any of the available technical libraries. You have two options, (if possible) modify existing function/indicator or create one from scratch. In this post, we will see how to use existing functions to create new indicator.

Let’s say I want to calculate EMA of RSI from our example strategy. Instead of supplying close column to the ema function, you can supply rsi column instead. The code will look like

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
    dataframe['ema_9'] = ta.EMA(dataframe['close'], 9)
    dataframe['ema_20'] = ta.EMA(dataframe['close'], 20)
    dataframe['rsi'] = ta.RSI(dataframe['close'], 14)
    dataframe['ema_9_rsi'] = ta.EMA(dataframe['rsi'], 9)
    return dataframe

The full strategy code will look like this

from freqtrade.strategy import IStrategy, informative
from pandas import DataFrame
import freqtrade.vendor.qtpylib.indicators as qtpylib
import talib.abstract as ta
from freqtrade.persistence import Trade
from datetime import datetime, timedelta
from typing import Optional, Union
class strat_template (IStrategy):
    def version(self) -> str:
        return "template-v1"
    INTERFACE_VERSION = 3
    minimal_roi = {
        "0": 0.05
    }
    stoploss = -0.05
    timeframe = '15m'
    process_only_new_candles = True
    startup_candle_count = 999
    use_custom_stoploss = True
    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float:
        
        sl_new = 1
        if (current_time - timedelta(minutes=15) >= trade.open_date_utc):
            dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
            current_candle = dataframe.iloc[-1].squeeze()
            current_profit = trade.calc_profit_ratio(current_candle['close'])
            if (current_profit >= 0.03):
                sl_new = 0.01
        return sl_new
    def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> Optional[Union[str, bool]]:
        if ((current_time - timedelta(minutes=15)) >= trade.open_date_utc):
            dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
            current_candle = dataframe.iloc[-1].squeeze()
            current_profit = trade.calc_profit_ratio(current_candle['close'])
            
            if (current_profit >= 0):
                if (current_candle['rsi'] >= 70):
                    return "rsi_overbought"
    @informative('30m')
    def populate_indicators_inf1(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        
        dataframe['rsi'] = ta.RSI(dataframe['close'], 14)
        return dataframe
    @informative('1h')
    def populate_indicators_inf2(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        
        dataframe['rsi'] = ta.RSI(dataframe['close'], 14)
        return dataframe
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['ema_9'] = ta.EMA(dataframe['close'], 9)
        dataframe['ema_20'] = ta.EMA(dataframe['close'], 20)
        dataframe['rsi'] = ta.RSI(dataframe['close'], 14)
        dataframe['ema_9_rsi'] = ta.EMA(dataframe['rsi'], 9)
        return dataframe
    
    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            qtpylib.crossed_above(dataframe['ema_9'], dataframe['ema_20'])
            &
            (dataframe['rsi_30m'] < 50)
            &
            (dataframe['rsi_1h'] < 30)
            &
            (dataframe['ema_9_rsi'] < 70)
            &
            (dataframe['volume'] > 0)
            , ['enter_long', 'enter_tag']
        ] = (1, 'golden cross')
        return dataframe
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            qtpylib.crossed_below(dataframe['ema_9'], dataframe['ema_20'])
            &
            (dataframe['volume'] > 0)
            , ['exit_long', 'exit_tag']
        ] = (1, 'death cross')
        return dataframe

3 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *