Skip to main content

Inverse Strategy Analysis

I. Strategy Overview

Inverse is a medium-to-long-term trend-following strategy based on the Inverse Fisher Transform of the Commodity Channel Index (CCI). The strategy cleverly applies mathematical transformation technology to convert CCI into more actionable signal indicators, combining multi-timeframe analysis and SSL channel confirmation to construct a complete trend trading system.

The strategy name "Inverse" directly derives from its core technique—the Inverse Fisher Transform. This mathematical transformation maps arbitrarily distributed data into a finite range, effectively smoothing noise signals while preserving key trend reversal characteristics. Through this technique, the strategy successfully converts complex oscillator indicators into clear buy/sell signals.

From a design philosophy perspective, the Inverse strategy belongs to the category combining trend-following and mean-reversion. It captures medium-to-long-term trend continuations while seeking rebound opportunities in oversold zones, achieving dual market opportunity capture. The strategy operates on a 1-hour cycle with 4-hour timeframe trend confirmation, suitable for medium-short-term traders.


II. Theoretical Foundation

2.1 Inverse Fisher Transform Principle

The Fisher Transform was first proposed by J.F. Ehlers as a mathematical method to convert any probability distribution into a normal distribution. Its formula:

Fisher(x) = 0.5 * ln((1 + x) / (1 - x))

The Inverse Fisher Transform is the inverse process of the Fisher Transform:

Inverse Fisher(x) = (exp(2x) - 1) / (exp(2x) + 1)

The core value of this transformation: it maps input data into the fixed range [-1, 1] while enhancing response sensitivity at boundary regions. When input approaches extremes, output changes more drastically—which perfectly meets trading signals' need for inflection point identification.

In the strategy, the Inverse Fisher Transform is applied to the CCI indicator with these processing steps:

  1. Calculate CCI values (period determined by parameter buy_fisher_length, default 31)
  2. Scale CCI: cci_scaled = 0.1 * (cci / 4)
  3. Calculate weighted moving average: wmacci = WMA(cci_scaled, 9)
  4. Apply Inverse Fisher Transform: fisher_cci = (exp(2*wmacci) - 1) / (exp(2*wmacci) + 1)

After this processing, Fisher CCI has these advantages:

  • Fixed value range [-1, 1], convenient for setting uniform thresholds
  • Better smoothness, fewer false signals
  • More sensitive to extreme values, identifies reversals faster

2.2 CCI Indicator Characteristics

Commodity Channel Index (CCI), developed by Donald Lambert, is a momentum indicator measuring how far the current price deviates from its historical average:

CCI = (Typical Price - SMA(TP, n)) / (0.015 * Mean Deviation)

Where:

  • Typical Price = (High + Low + Close) / 3
  • SMA(TP, n) = n-period simple moving average of typical price
  • Mean Deviation = Mean absolute deviation of typical price from its moving average

Traditional CCI interpretation:

  • CCI > +100: Overbought zone, possible pullback
  • CCI < -100: Oversold zone, possible rebound
  • CCI within ±100: Normal fluctuation zone

Reasons for choosing CCI as the base indicator:

  1. CCI has no upper limit, can more truly reflect extreme conditions
  2. CCI responds quickly to trend changes
  3. After Inverse Fisher Transform, CCI's overbought/oversold characteristics become more pronounced

2.3 SSL Channels Principle

SSL (SSL Channels) is a trend judgment indicator determining market direction by calculating price's upper and lower channels. The strategy's SSL channel implementation:

def SSLChannels(self, dataframe, length = 7):
df['ATR'] = ATR(dataframe, 14)
df['smaHigh'] = df['high'].rolling(length).mean() + df['ATR']
df['smaLow'] = df['low'].rolling(length).mean() - df['ATR']
df['hlv'] = np.where(df['close'] > df['smaHigh'], 1,
np.where(df['close'] < df['smaLow'], -1, np.NAN))
df['hlv'] = df['hlv'].ffill()
df['sslDown'] = np.where(df['hlv'] < 0, df['smaHigh'], df['smaLow'])
df['sslUp'] = np.where(df['hlv'] < 0, df['smaLow'], df['smaHigh'])
return df['sslDown'], df['sslUp']

SSL channel core logic:

  1. Calculate SMA high/low channels: Based on price mean ± ATR volatility
  2. Judge trend state: Close breaks above upper rail for bullish (hlv=1), breaks below lower rail for bearish (hlv=-1)
  3. Trend state continuation: Use forward fill to maintain trend state until next breakout
  4. Generate upper/lower rails: Dynamically switch upper/lower rail positions based on trend state

SSL channel advantage: combines trend judgment with volatility adaptation, effectively filtering false signals in ranging markets.


III. Strategy Architecture

3.1 Timeframe Design

The strategy uses a dual-timeframe architecture:

Primary Timeframe (1 hour)

  • Generates buy/sell signals
  • Calculates granular Fisher CCI indicators
  • Executes entry and exit operations

Informative Timeframe (4 hours)

  • Confirms trend direction
  • Calculates SSL channels and EMA moving averages
  • Provides higher-level market context

Advantages of this design:

  1. Uses 4-hour trend stability to avoid counter-trend trades
  2. Finds precise entry points on 1-hour timeframe, improving trading efficiency
  3. When both timeframes align, win rate significantly improves

3.2 Parameter System

The strategy uses a Hyperopt-optimizable parameter system:

Buy Parameters

ParameterDefaultOptimization RangeDescription
buy_fisher_length31[13, 55]Fisher CCI calculation period
buy_fisher_cci_1-0.42[-0.6, -0.3]Primary entry threshold
buy_fisher_cci_20.41[0.3, 0.6]Secondary entry threshold

Sell Parameters

ParameterDefaultOptimization RangeDescription
sell_fisher_cci_10.42[0.3, 0.6]Primary exit threshold
sell_fisher_cci_2-0.34[-0.6, -0.3]Secondary exit threshold

Stop Loss/Take Profit Parameters

ParameterValueDescription
stoploss-0.2Fixed stop loss 20%
trailing_stopTrueEnable trailing stop
trailing_stop_positive0.078Start trailing after 7.8% profit
trailing_stop_positive_offset0.174Trailing stop start offset 17.4%
minimal_roi{"0": 0.10, "30": 0.05, "60": 0.02}Staged take profit

3.3 Indicator Calculation Process

The strategy's indicator calculation is divided into two parts:

Informative Timeframe Indicators (4 hours)

def informative_indicators(self, dataframe, metadata):
# EMA system
informative_p['ema_50'] = ta.EMA(informative_p, timeperiod=50)
informative_p['ema_100'] = ta.EMA(informative_p, timeperiod=100)
informative_p['ema_200'] = ta.EMA(informative_p, timeperiod=200)

# SSL channels
ssl_down, ssl_up = self.SSLChannels(informative_p, 20)
informative_p['ssl_down'] = ssl_down
informative_p['ssl_up'] = ssl_up

Primary Timeframe Indicators (1 hour)

def normal_tf_indicators(self, dataframe, metadata):
# Fisher CCI calculation
for cci_length in self.buy_fisher_length.range:
dataframe[f'cci'] = ta.CCI(dataframe, timeperiod=cci_length)
cci = 0.1 * (dataframe[f'cci'] / 4)
wmacci = ta.WMA(cci, timeperiod=9)
dataframe[f'fisher_cci_{cci_length}'] = (numpy.exp(2 * wmacci) - 1) / (numpy.exp(2 * wmacci) + 1)

# Trend confirmation indicators
dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)
dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200)
dataframe['adx'] = ta.ADX(dataframe, timeperiod=3)
dataframe['di_up'] = ta.PLUS_DI(dataframe, timeperiod=3) > ta.MINUS_DI(dataframe, timeperiod=3)

IV. Entry Logic

4.1 Entry Conditions Detailed

The strategy's entry logic uses composite conditions requiring all conditions to be met simultaneously:

Condition Group 1: Fisher CCI Signal

(qtpylib.crossed_above(dataframe[f'fisher_cci_{self.buy_fisher_length.value}'], self.buy_fisher_cci_1.value))
|
(
(qtpylib.crossed_below(dataframe[f'fisher_cci_{self.buy_fisher_length.value}'], self.buy_fisher_cci_2.value).rolling(8).max() == 1) &
(qtpylib.crossed_above(dataframe[f'fisher_cci_{self.buy_fisher_length.value}'], self.buy_fisher_cci_2.value))
)

This includes two entry scenarios:

Scenario A: Oversold Rebound Entry

  • Fisher CCI crosses above -0.42 threshold
  • Most direct entry signal, capturing rebounds from oversold zones

Scenario B: Trend Confirmation Entry

  • Fisher CCI has crossed below 0.41 within the past 8 candles
  • Currently Fisher CCI crosses above 0.41
  • Captures pullback entries during trend continuation

Condition Group 2: Multi-Timeframe Trend Confirmation

(dataframe[f'ssl_up_{self.info_timeframe}'] > dataframe[f'ssl_down_{self.info_timeframe}']) &
(dataframe['ema_50'] > dataframe['ema_200']) &
(dataframe[f'ema_50_{self.info_timeframe}'] > dataframe[f'ema_100_{self.info_timeframe}']) &
(dataframe[f'ema_50_{self.info_timeframe}'] > dataframe[f'ema_200_{self.info_timeframe}'])

Four trend conditions must all be met simultaneously:

  1. 4-hour SSL channel bullish: ssl_up > ssl_down, confirms medium-term upward trend
  2. 1-hour EMA bullish alignment: EMA50 > EMA200, confirms short-term upward trend
  3. 4-hour EMA bullish alignment (1): EMA50 > EMA100, confirms medium-term momentum
  4. 4-hour EMA bullish alignment (2): EMA50 > EMA200, confirms medium-term trend

Condition Group 3: Volume Filter

(dataframe['volume'] > 0)

Ensures sufficient market liquidity.


V. Exit Logic

5.1 Sell Signal Conditions

The strategy's exit logic is relatively concise, primarily relying on Fisher CCI inflection signals:

def populate_exit_trend(self, dataframe, metadata):
dataframe.loc[
(
(qtpylib.crossed_below(dataframe[f'fisher_cci_{self.buy_fisher_length.value}'], self.sell_fisher_cci_1.value))
| (qtpylib.crossed_below(dataframe[f'fisher_cci_{self.buy_fisher_length.value}'], self.sell_fisher_cci_2.value))
) &
(dataframe['volume'] > 0)
), 'sell'] = 1

Sell conditions include two scenarios:

Scenario 1: High-Point Reversal Sell

  • Fisher CCI crosses below 0.42
  • Captures trend reversal from overbought zone

Scenario 2: Trend Weakening Sell

  • Fisher CCI crosses below -0.34
  • Exits when bullish momentum clearly weakens

5.2 Exit Confirmation Mechanism

The strategy implements a confirm_trade_exit method for secondary confirmation of sell signals:

def confirm_trade_exit(self, pair, trade, order_type, amount, rate, time_in_force, sell_reason, current_time, **kwargs):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1]
previous_candle_1 = dataframe.iloc[-2]

if (last_candle is not None):
if (sell_reason in ['sell_signal']):
if last_candle['di_up'] and (last_candle['adx'] > previous_candle_1['adx']):
return False
return True

Exit confirmation logic:

  • Only filters sells triggered by sell_signal
  • If current DI+ > DI- (bullish momentum dominates) AND ADX rising (trend strength increasing)
  • Then reject the sell, continue holding

This is a protection mechanism against being shaken out during strong trends.

5.3 Stop Loss and Take Profit Mechanism

Fixed Stop Loss

  • Stop-loss ratio: -20%
  • Auto-close when loss reaches 20%

Trailing Stop

trailing_stop = True
trailing_stop_positive = 0.078
trailing_stop_positive_offset = 0.174
trailing_only_offset_is_reached = False

Trailing stop logic:

  1. When profit reaches 7.8%, activate trailing stop
  2. Stop line retreats a fixed ratio from the highest point
  3. trailing_only_offset_is_reached = False means trailing starts immediately without waiting for offset value

Staged Take Profit (ROI)

minimal_roi = {
"0": 0.10, # Effective immediately after opening: 10% target
"30": 0.05, # After 30 minutes: 5% target
"60": 0.02 # After 60 minutes: 2% target
}

ROI mechanism: encourages quick profit-taking, avoids long-holding risk.


VI. Risk Control System

6.1 Multi-Layer Risk Control Architecture

The strategy builds a complete multi-layer risk control system:

Layer 1: Signal Filtering

  • Fisher CCI threshold filtering, avoids noisy signals
  • Trend confirmation filtering, avoids counter-trend trades
  • Volume filtering, ensures liquidity

Layer 2: Trend Confirmation

  • Dual-timeframe trend consistency verification
  • Multi-dimensional moving average system confirmation
  • SSL channel direction confirmation

Layer 3: Position Management

  • Fixed stop loss protects principal
  • Trailing stop locks in profits
  • Staged take profit controls risk exposure

Layer 4: Exit Confirmation

  • ADX/DI trend strength filtering
  • Prevents being shaken out during strong trends

6.2 Risk Control Parameter Analysis

Risk Control TypeParameter ValueRisk LevelMechanism
Fixed Stop Loss-20%Medium-HighProtects principal, prevents large single losses
Trailing Activation7.8%LowProtects after sufficient profit
Trailing Offset17.4%LowEnsures sufficient profit buffer
ROI Stage 110%LowQuick profit-taking
ROI Stage 25%MediumReduce expectations after 30 minutes
ROI Stage 32%MediumQuick exit after 60 minutes

6.3 Market Adaptability Analysis

Suitable markets:

  • Markets with clear unilateral trends
  • Trading instruments with moderate volatility
  • Trading pairs with sufficient liquidity

Unsuitable markets:

  • Severely oscillating sideways markets
  • Low-liquidity small-cap coins
  • Extreme conditions (wild spikes or crashes)

VII. Parameter Optimization Space

7.1 Optimizable Parameters

Buy parameter ranges

  • buy_fisher_length: [13, 55], affects Fisher CCI sensitivity
  • buy_fisher_cci_1: [-0.6, -0.3], controls oversold entry threshold
  • buy_fisher_cci_2: [0.3, 0.6], controls trend pullback entry threshold

Sell parameter ranges

  • sell_fisher_cci_1: [0.3, 0.6], controls overbought exit threshold
  • sell_fisher_cci_2: [-0.6, -0.3], controls trend weakening exit threshold

7.2 Optimization Suggestions

  1. Data preparation: Ensure at least 6 months of historical data, covering different market states
  2. Optimization method: Use Hyperopt's Sharpe Ratio as objective, set reasonable parameter boundaries
  3. Out-of-sample verification: Validate parameters on data not used in optimization

VIII. Live Trading Recommendations

8.1 Deployment Preparation

Environment configuration

timeframe = '1h'
startup_candle_count = 200
process_only_new_candles = True

Trading pair selection: Choose mainstream pairs with sufficient liquidity, avoid new coins and low-market-cap coins

8.2 Risk Warnings

  1. Trend failure risk: May generate consecutive losses at trend turning points—recommend setting circuit breakers after consecutive losses
  2. Slippage risk: Strategy uses limit orders for buying—in fast markets, may not fill
  3. Parameter failure risk: Optimized parameters may fail when market conditions change—recommend regular re-optimization

IX. Strategy Strengths and Limitations

9.1 Strategy Strengths

Technical advantages:

  1. Indicator innovation: Inverse Fisher Transform enhances signal quality
  2. Multi-timeframe: Uses 4-hour confirmation to reduce false signals
  3. Composite conditions: Multi-filter conditions improve signal reliability
  4. Dynamic risk control: Trailing stop and staged take profit

Practical advantages:

  1. Optimizable: All key parameters support Hyperopt
  2. Clear logic: Entry/exit rules are explicit, easy to understand and maintain
  3. Good visualization: Provides plot_config, convenient for analysis
  4. High computational efficiency: Moderate indicator calculation volume, suitable for real-time trading

9.2 Strategy Limitations

Technical limitations:

  1. Trend dependency: Underperforms in ranging markets
  2. Lagging: EMA system has inherent lag
  3. Parameter sensitivity: Different market environments need different parameters
  4. Single indicator: Primarily relies on Fisher CCI, lacks multi-indicator verification

Practical limitations:

  1. Large stop loss: 20% may exceed some traders' risk tolerance
  2. Aggressive trailing stop: 7.8% trigger threshold may lock in profits too early
  3. Simple exit: Exit conditions relatively simpler than entry
  4. No position building mechanism: Doesn't leverage trending advantages to add positions

X. Improvement Directions

10.1 Indicator-Level Improvements

# Suggested additions
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe['macd'] = ta.MACD(dataframe)
dataframe['bb_upperband'] = ta.BBANDS(dataframe, timeperiod=20)['upperband']

10.2 Logic-Level Improvements

Enhanced exit logic: Add RSI divergence detection, MACD death cross confirmation, price pattern recognition

Improved stop-loss mechanism:

# Suggested ATR dynamic stop loss
dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
stoploss = -2 * dataframe['atr'] / dataframe['close']

Added position management:

# Adjust position size based on ADX strength
position_size = base_size * (adx / 25)

XI. Summary

The Inverse strategy is a well-designed trend-following strategy. Its core innovation—applying the Inverse Fisher Transform to the CCI indicator—effectively enhances signal quality. Through multi-timeframe analysis and composite filtering conditions, the strategy achieves effective capture of trending markets while maintaining signal accuracy.

The strategy's main value:

  1. Solid mathematical theory: Inverse Fisher Transform has clear mathematical meaning
  2. Complete risk control: Multi-layer protection safeguards principal and profits
  3. High optimizability: Parameter system supports Hyperopt automatic optimization
  4. High live-trading usability: Clear logic, efficient computation

The strategy's main risk lies in its dependence on trending markets—may generate many false signals in oscillating markets. Traders are recommended to:

  1. Choose trading pairs with strong trends
  2. Adjust parameters according to market environment
  3. Strictly control per-trade risk
  4. Regularly monitor and optimize the strategy

Overall, the Inverse strategy provides a reliable framework for quantitative traders. With appropriate optimization and improvement, its performance across different market environments can be further enhanced.