On this page
Simple Crossover Signal Bars for Visual Backtesting - Technical Guide
Plots colored bars in a separate pane when fast SMA crosses above (green) or below (red) slow SMA.
| Language | Indie Script v5 |
| Platform | TakeProfit |
| Category | Moving averages |
| Type | Indicator |
| Author | @mustermann84 on TakeProfit |
| License | MIT |
| Live script | Open on TakeProfit |
| Source file | Simple Crossover Signal Bars for Visual Backtesting.indie5 |
Overview
This indicator detects crossovers between a fast and a slow simple moving average (SMA) of the closing price. It is intended for trend-following or visual backtesting: bullish crossovers (fast MA crossing above slow MA) are highlighted with green bars, bearish crossovers (fast crossing below slow) with red bars, and neutral periods show no bar. The indicator runs in a separate window below the price chart with a dashed gray midline at 0 for reference.
How it works
- Compute the fast SMA of the close price using the user-set period (
fast_ma_length, default 50). - Compute the slow SMA of the close price using the user-set period (
slow_ma_length, default 200). - Compare the current bar’s SMA values with the previous bar’s values to detect a crossover: fast > slow and previously fast ≤ slow means bullish crossover; fast < slow and previously fast ≥ slow means bearish crossover.
- Store a signal value: +1 for bullish, -1 for bearish, 0 otherwise in a
MutSeriesFseries. - Assign a plot color based on the signal: green for +1, red for -1, fully transparent for 0.
- Return a
plot.Columnsobject with the signal value and color, plotted in a separate pane with a midline at 0.
Logic flow
flowchart TD
A["Compute Fast SMA"]
B["Compute Slow SMA"]
C{"fast_ma[0] > slow_ma[0] and fast_ma[1] <= slow_ma[1]?"}
D{"fast_ma[0] < slow_ma[0] and fast_ma[1] >= slow_ma[1]?"}
E["signal_value = 1"]
F["signal_value = -1"]
G["signal_value = 0"]
H["Set plot color: GREEN, RED, or transparent"]
I["Return Columns(signal, color)"]
A --> B
B --> C
C -- yes --> E
C -- no --> D
D -- yes --> F
D -- no --> G
E --> H
F --> H
G --> H
H --> I
Parameters
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
fast_ma_length |
int | 50 | ≥ 1 | Fast MA Length |
slow_ma_length |
int | 200 | ≥ 1 | Slow MA Length |
Code walkthrough
Parameter and Plot Setup
Lines 5-9 of Simple Crossover Signal Bars for Visual Backtesting.indie5:
@indicator('Simple Crossover Signal Bars for Visual Backtesting', overlay_main_pane=False)
@param.int('fast_ma_length', default=50, min=1, title='Fast MA Length')
@param.int('slow_ma_length', default=200, min=1, title='Slow MA Length')
@plot.columns(title='Crossover Signal', id='#plot_0')
@level(value=0, title='Mittellinie', line_color=color.GRAY, line_style=line_style.DASHED, line_width=1)
The indicator is registered with overlay_main_pane=False so it appears in a separate pane. Two integer parameters (fast_ma_length and slow_ma_length) are exposed in the settings UI. A @plot.columns decorator configures the histogram output, and a @level adds a dashed gray midline at 0.
Crossover Detection Logic
Lines 16-23 of Simple Crossover Signal Bars for Visual Backtesting.indie5:
signal_value = MutSeriesF.new(init=0)
if fast_ma[0] > slow_ma[0] and fast_ma[1] <= slow_ma[1]:
signal_value[0] = 1 # Bullisches Signal
elif fast_ma[0] < slow_ma[0] and fast_ma[1] >= slow_ma[1]:
signal_value[0] = -1 # Bärisches Signal
else:
signal_value[0] = 0 # Kein Signal
A MutSeriesF named signal_value is initialized to 0 for each bar. Using the current (index 0) and previous (index 1) values of the two SMAs, the code checks for a bullish crossover (fast crosses above slow) or bearish crossover (fast crosses below slow). If neither condition holds, the signal remains 0. The MutSeriesF stores the signal for the current bar, which is later used for the plot.
Dynamic Color Assignment
Lines 26-30 of Simple Crossover Signal Bars for Visual Backtesting.indie5:
plot_color = (
color.GREEN if signal_value[0] == 1
else color.RED if signal_value[0] == -1
else color.rgba(0, 0, 0, 0) # Transparent, wenn kein Signal
)
The plot color is chosen based on the current signal value: green for bullish, red for bearish, and a fully transparent rgba(0,0,0,0) when there is no signal. This hides bars during neutral periods while still allowing the indicator to occupy a pane.
Reading the chart
- Green bar at value 1: Bullish crossover – fast MA crossed above slow MA.
- Red bar at value -1: Bearish crossover – fast MA crossed below slow MA.
- No bar (transparent): No crossover occurred on that bar.
- The dashed gray line at 0 serves as a midline to quickly distinguish positive (bullish) from negative (bearish) signals.
- Bars are plotted in a separate window below the price chart, not overlaid on price.
Implementation notes
- Both SMAs must have at least
max(fast_ma_length, slow_ma_length)bars of data before a valid crossover can be detected; earlier bars will show no signal due to NaN values in the SMA series. - The signal is derived purely from the current and previous bar’s SMA values – it is not repainted once a bar closes.
- The transparent color for neutral signals (
color.rgba(0,0,0,0)) effectively hides the column, so no bar is drawn when there is no crossover. - The indicator operates on the chart’s primary timeframe; multi-timeframe analysis requires modifying the source or using
sec_context.
FAQ
Can I change the moving average type from SMA to EMA or others?
Yes, replace Sma.new with the desired algorithm (e.g., Ema.new) and adjust the import accordingly. The crossover logic remains the same.
Why do no bars appear on my chart?
The indicator requires enough bars to compute both SMAs (e.g., at least 200 bars for default settings). Also ensure the indicator is added to a separate pane (not overlaid on price).
Can I use this indicator for real-time trading?
Yes, the signal updates on each new bar based on the close price. However, crossovers may lag due to the slow MA length; this is a characteristic of lagging moving average systems.
Full source code
Indie Script v5, as published on TakeProfit. Copy it into the platform’s script editor or open the live script.
# indie:lang_version = 5
from indie import indicator, plot, color, MutSeriesF, level, line_style, param
from indie.algorithms import Sma
@indicator('Simple Crossover Signal Bars for Visual Backtesting', overlay_main_pane=False)
@param.int('fast_ma_length', default=50, min=1, title='Fast MA Length')
@param.int('slow_ma_length', default=200, min=1, title='Slow MA Length')
@plot.columns(title='Crossover Signal', id='#plot_0')
@level(value=0, title='Mittellinie', line_color=color.GRAY, line_style=line_style.DASHED, line_width=1)
def Main(self, fast_ma_length, slow_ma_length):
# Berechnung der gleitenden Durchschnitte
fast_ma = Sma.new(self.close, fast_ma_length) # Einstellbare Länge für den schnellen MA
slow_ma = Sma.new(self.close, slow_ma_length) # Einstellbare Länge für den langsamen MA
# Signal-Logik: 1 für bullisches Crossover, -1 für bärisches Crossover
signal_value = MutSeriesF.new(init=0)
if fast_ma[0] > slow_ma[0] and fast_ma[1] <= slow_ma[1]:
signal_value[0] = 1 # Bullisches Signal
elif fast_ma[0] < slow_ma[0] and fast_ma[1] >= slow_ma[1]:
signal_value[0] = -1 # Bärisches Signal
else:
signal_value[0] = 0 # Kein Signal
# Farbe basierend auf dem Signalwert
plot_color = (
color.GREEN if signal_value[0] == 1
else color.RED if signal_value[0] == -1
else color.rgba(0, 0, 0, 0) # Transparent, wenn kein Signal
)
# Rückgabe der Balkenanzeige
return plot.Columns(value=signal_value[0], color=plot_color)