0bps

Strategy vault / Trend following

BlackBit Trader XO Macro Trend Scanner Strategy

This strategy combines double moving average and StochRSI indicator to identify trend direction and entry points. The main feature is that it can enter the market in the early stage of trend, while using the…

Author
ChaoZhang
Complexity
Intermediate · 191 lines
Parameters
33
Backtest bar
1h · intraday
Tested on
BTC/USDT · futures

IMG

Overview

This strategy combines double moving average and StochRSI indicator to identify trend direction and entry points. The main feature is that it can enter the market in the early stage of trend, while using the overbought/oversold characteristics of StochRSI to filter false breakouts.

Strategy Logic

The strategy uses fast moving average EMA(12) and slow moving average EMA(25) to build a double moving average system. When fast line crosses above slow line, buy signal is generated. When fast line crosses below slow line, sell signal is generated. This is used to determine the major trend direction.

At the same time, the strategy incorporates StochRSI crossover to further identify entry timing. StochRSI combines stochastic KDJ and RSI. When K line crosses D line upward from oversold zone, buy signal is generated. When K line crosses D line downward from overbought zone, sell signal is generated.

Only when double moving average produces signal and StochRSI also produces corresponding signal, this strategy will open positions. This can effectively filter out some false breakouts and avoid invalid trades.

Advantage Analysis

The biggest advantage of this strategy is being able to judge trend direction and potential entry points early. The moving average system can produce signals at the beginning of a trend, while the addition of StochRSI effectively filters false breakouts and avoids erroneous trades.

In addition, the strategy combines both trend analysis and overbought/oversold judgment, featuring the strengths of both trend following and mean-reversion. Whether tracking trends or buying low and selling high, this strategy can capture opportunities in all aspects.

Risk Analysis

The main risk of this strategy lies in the lag of the double moving average system itself. When the market changes violently in a sudden, the double moving average system often takes time to generate signals, easily missing the best entry timing.

In addition, StochRSI may also generate false signals, leading to unnecessary trades, especially in ranging markets where K and D line can frequently crossover, posing risks of excessive invalid operations.

Optimization Directions

The optimization of this strategy mainly focuses on several aspects:

  1. Adjust the parameters of double moving average to adopt moving average periods more conducive to capturing trends;

  2. Optimize the parameters of StochRSI to come up with more sensible overbought/oversold criteria;

  3. Increase order size or adjust stop loss/take profit to pursue higher return;

  4. Incorporate other indicators as filter conditions to further reduce invalid signals.

Summary

Overall, this strategy is very suitable for capturing medium-to-long term trends, with great profit potential in early stage of trends. Combining StochRSI as an auxiliary judge can effectively filter misleading signals and avoid unnecessary losses. With improvements in parameter tuning and risk management, this strategy can become a powerful tool to obtain steady returns.

Parameters

NameDefaultWhat it controls
v_input_1_close0OHLC Type: close | high | low | open | hl2 | hlc3 | hlcc4 | ohlc4
v_input_212Fast EMA
v_input_325Slow EMA
v_input_425Consolidated EMA
v_input_5trueShow Both EMAs
v_input_int_13K
v_input_int_23D
v_input_int_314RSI Length
v_input_int_414Stochastic Length
v_input_int_580(?Bands change this instead of length in Style for Stoch RSI colour to work properly)Upper Band
v_input_int_650Middle Band
v_input_int_720Lower Band
v_input_bool_1false(?Crossover Alerts)Crossover Alert Background Colour (Middle Level) [ON/OFF]
v_input_bool_2falseCrossover Alert Background Colour (OB/OS Level) [ON/OFF]
v_input_bool_3falseCrossover Alert >input [ON/OFF]
v_input_bool_4falseCrossover Alert <input [ON/OFF]
v_input_string_10(?Moving Average)MA Type: EMA | WMA | SMA | None
v_input_source_1_close0MA Source: close | high | low | open | hl2 | hlc3 | hlcc4 | ohlc4
v_input_int_8200MA Length
v_input_6timestamp(2000-12-24T00:00:00)(?---------TIME RANGE SETTINGS---------)startDate
v_input_7timestamp(2029-02-26T00:00:00)finishDate
v_input_8200(?EMA FILTER SETTINGS)EMA Filter Length
v_input_9_close0EMA Filter Source: close | high | low | open | hl2 | hlc3 | hlcc4 | ohlc4
v_input_1026(?MACD FILTER SETTINGS)Fast Length
v_input_11100Slow Length
v_input_12_close0Source: close | high | low | open | hl2 | hlc3 | hlcc4 | ohlc4
v_input_int_99Signal Smoothing
v_input_string_20Oscillator MA Type: EMA | SMA
v_input_string_30Signal Line MA Type: EMA | SMA
v_input_float_10.3(?TP/SL CONDITION INPUTS HERE)Enter The Take Profit %
v_input_float_20.16Enter The Stop %
v_input_13Long entry(?ALERT MESSAGE SETTINGS)Long entry alert
v_input_14Short entryShort entry alert

Source Pine Script

/*backtest
start: 2024-01-01 00:00:00
end: 2024-01-24 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © btc_charlie / @TheParagonGrp

//@version=5
strategy('BlackBit Trader XO Macro Trend Scanner', overlay=true)

// Variables
var ok = 0
var countBuy = 0
var countSell = 0
src = input(close, title='OHLC Type')
i_fastEMA = input(12, title='Fast EMA')
i_slowEMA = input(25, title='Slow EMA')
i_defEMA = input(25, title='Consolidated EMA')

// Allow the option to show single or double EMA
i_bothEMAs = input(title='Show Both EMAs', defval=true)

// Define EMAs
v_fastEMA = ta.ema(src, i_fastEMA)
v_slowEMA = ta.ema(src, i_slowEMA)
v_biasEMA = ta.ema(src, i_defEMA)

// Color the EMAs
emaColor = v_fastEMA > v_slowEMA ? color.green : v_fastEMA < v_slowEMA ? color.red : #FF530D

// Plot EMAs
plot(i_bothEMAs ? na : v_biasEMA, color=emaColor, linewidth=3, title='Consolidated EMA')
plot(i_bothEMAs ? v_fastEMA : na, title='Fast EMA', color=emaColor)
plot(i_bothEMAs ? v_slowEMA : na, title='Slow EMA', color=emaColor)

// Colour the bars
buy = v_fastEMA > v_slowEMA
sell = v_fastEMA < v_slowEMA

if buy
    countBuy += 1
    countBuy

if buy
    countSell := 0
    countSell

if sell
    countSell += 1
    countSell

if sell
    countBuy := 0
    countBuy

buysignal = countBuy < 2 and countBuy > 0 and countSell < 1 and buy and not buy[1]
sellsignal = countSell > 0 and countSell < 2 and countBuy < 1 and sell and not sell[1]

barcolor(buysignal ? color.green : na)
barcolor(sellsignal ? color.red : na)


bull = countBuy > 1
bear = countSell > 1

barcolor(bull ? color.green : na)
barcolor(bear ? color.red : na)

// Set Alerts

// alertcondition(ta.crossover(v_fastEMA, v_slowEMA), title='Bullish EMA Cross', message='Bullish EMA crossover')
// alertcondition(ta.crossunder(v_fastEMA, v_slowEMA), title='Bearish EMA Cross', message='Bearish EMA Crossover')

// Stoch RSI code

smoothK = input.int(3, 'K', minval=1)
smoothD = input.int(3, 'D', minval=1)
lengthRSI = input.int(14, 'RSI Length', minval=1)
lengthStoch = input.int(14, 'Stochastic Length', minval=1)

rsi1 = ta.rsi(src, lengthRSI)
k = ta.sma(ta.stoch(rsi1, rsi1, rsi1, lengthStoch), smoothK)
d = ta.sma(k, smoothD)

bandno0 = input.int(80, minval=1, title='Upper Band', group='Bands (change this instead of length in Style for Stoch RSI colour to work properly)')
bandno2 = input.int(50, minval=1, title='Middle Band', group='Bands (change this instead of length in Style for Stoch RSI colour to work properly)')
bandno1 = input.int(20, minval=1, title='Lower Band', group='Bands (change this instead of length in Style for Stoch RSI colour to work properly)')

// Alerts

crossoverAlertBgColourMidOnOff = input.bool(title='Crossover Alert Background Colour (Middle Level) [ON/OFF]', group='Crossover Alerts', defval=false)
crossoverAlertBgColourOBOSOnOff = input.bool(title='Crossover Alert Background Colour (OB/OS Level) [ON/OFF]', group='Crossover Alerts', defval=false)

crossoverAlertBgColourGreaterThanOnOff = input.bool(title='Crossover Alert >input [ON/OFF]', group='Crossover Alerts', defval=false)
crossoverAlertBgColourLessThanOnOff = input.bool(title='Crossover Alert <input [ON/OFF]', group='Crossover Alerts', defval=false)

maTypeChoice = input.string('EMA', title='MA Type', group='Moving Average', options=['EMA', 'WMA', 'SMA', 'None'])
maSrc = input.source(close, title='MA Source', group='Moving Average')
maLen = input.int(200, minval=1, title='MA Length', group='Moving Average')

maValue = if maTypeChoice == 'EMA'
    ta.ema(maSrc, maLen)
else if maTypeChoice == 'WMA'
    ta.wma(maSrc, maLen)
else if maTypeChoice == 'SMA'
    ta.sma(maSrc, maLen)
else
    0

crossupCHECK = maTypeChoice == 'None' or open > maValue and maTypeChoice != 'None'
crossdownCHECK = maTypeChoice == 'None' or open < maValue and maTypeChoice != 'None'

crossupalert = crossupCHECK and ta.crossover(k, d) and (k < bandno2 or d < bandno2)
crossdownalert = crossdownCHECK and ta.crossunder(k, d) and (k > bandno2 or d > bandno2)
crossupOSalert = crossupCHECK and ta.crossover(k, d) and (k < bandno1 or d < bandno1)
crossdownOBalert = crossdownCHECK and ta.crossunder(k, d) and (k > bandno0 or d > bandno0)

aboveBandalert = ta.crossunder(k, bandno0)
belowBandalert = ta.crossover(k, bandno1)

bgcolor(color=crossupalert and crossoverAlertBgColourMidOnOff ? #4CAF50 : crossdownalert and crossoverAlertBgColourMidOnOff ? #FF0000 : na, title='Crossover Alert Background Colour (Middle Level)', transp=70)
bgcolor(color=crossupOSalert and crossoverAlertBgColourOBOSOnOff ? #fbc02d : crossdownOBalert and crossoverAlertBgColourOBOSOnOff ? #000000 : na, title='Crossover Alert Background Colour (OB/OS Level)', transp=70)

bgcolor(color=aboveBandalert and crossoverAlertBgColourGreaterThanOnOff ? #ff0014 : crossdownalert and crossoverAlertBgColourMidOnOff ? #FF0000 : na, title='Crossover Alert - K > Upper level', transp=70)
bgcolor(color=belowBandalert and crossoverAlertBgColourLessThanOnOff ? #4CAF50 : crossdownalert and crossoverAlertBgColourMidOnOff ? #FF0000 : na, title='Crossover Alert - K < Lower level', transp=70)

// alertcondition(crossupalert or crossdownalert, title='Stoch RSI Crossover', message='STOCH RSI CROSSOVER')

// Calculate start/end date and time condition
startDate = input(timestamp('2000-12-24T00:00:00'),group = "---------TIME RANGE SETTINGS---------")
finishDate = input(timestamp('2029-02-26T00:00:00'),group = "---------TIME RANGE SETTINGS---------")
time_cond = true


//ema filter
emalen = input(200,"EMA Filter Length",group = "EMA FILTER SETTINGS")
emasource = input(close,"EMA Filter Source",group = "EMA FILTER SETTINGS")
ema_fil = ta.ema(emasource,emalen)
plot(ema_fil,"EMA Filter")

//macd
fast_length = input(title="Fast Length", defval=26,group = "MACD FILTER SETTINGS")
slow_length = input(title="Slow Length", defval=100,group = "MACD FILTER SETTINGS")
src_macd = input(title="Source", defval=close,group = "MACD FILTER SETTINGS")
signal_length = input.int(title="Signal Smoothing",  minval = 1, maxval = 50, defval = 9,group = "MACD FILTER SETTINGS")
sma_source = input.string(title="Oscillator MA Type",  defval="EMA", options=["SMA", "EMA"],group = "MACD FILTER SETTINGS")
sma_signal = input.string(title="Signal Line MA Type", defval="EMA", options=["SMA", "EMA"],group = "MACD FILTER SETTINGS")

// Calculating
fast_ma = sma_source == "SMA" ? ta.sma(src_macd, fast_length) : ta.ema(src_macd, fast_length)
slow_ma = sma_source == "SMA" ? ta.sma(src_macd, slow_length) : ta.ema(src_macd, slow_length)
macd = fast_ma - slow_ma
signal = sma_signal == "SMA" ? ta.sma(macd, signal_length) : ta.ema(macd, signal_length)
hist = macd - signal

//tpsl
takeprofit=input.float(defval=0.3,title="Enter The Take Profit %",group="TP/SL CONDITION INPUTS HERE")/100
stoploss=input.float(defval=0.16,title="Enter The Stop %",group="TP/SL CONDITION INPUTS HERE")/100
tp = strategy.opentrades.entry_price(0)*takeprofit/syminfo.mintick
sl = strategy.opentrades.entry_price(0)*stoploss/syminfo.mintick

lg_rule = buysignal and hist > 0 and close > ema_fil
sh_rule = sellsignal and hist < 0 and close < ema_fil

// Plot Bull/Bear

plotshape(lg_rule, title='Bull', text='Bull', style=shape.triangleup, location=location.belowbar, color=color.new(color.green, 0), textcolor=color.new(color.black, 0), size=size.tiny)
plotshape(sh_rule, title='Bear', text='Bear', style=shape.triangledown, location=location.abovebar, color=color.new(color.red, 0), textcolor=color.new(color.black, 0), size=size.tiny)

//alert
lg_entryal = input("Long entry","Long entry alert",group = "ALERT MESSAGE SETTINGS")
sh_entryal = input("Short entry","Short entry alert",group = "ALERT MESSAGE SETTINGS")

if lg_rule and time_cond and barstate.isconfirmed
    strategy.entry("LONG",strategy.long)
    alert(lg_entryal,alert.freq_once_per_bar_close)
if strategy.position_size > 0
    strategy.exit("LONG EX","LONG",loss = sl,profit = tp,comment_loss = "LONG SL",comment_profit = "LONG TP")

if sh_rule and time_cond and barstate.isconfirmed
    strategy.entry("SHORT",strategy.short)
    alert(sh_entryal,alert.freq_once_per_bar_close)

if strategy.position_size < 0
    strategy.exit("SHORT EX","SHORT",loss = sl,profit = tp,comment_loss = "SHORT SL",comment_profit = "SHORT TP")

//end

Published by ChaoZhang on the FMZ strategy square · last modified 2024-01-25. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.

Build this with AgenKit

A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.

in Claude Code, Cursor, Codex & 4 more
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/BlackBit-Trader-XO-Macro-Trend-Scanner-Strategy.md
  1. npx agenkit install engineering-kit in your project
  2. Paste the command into your agent and approve each phase
  3. Get tests, backtest, risk controls and a paper-trading switch

Understand it first

Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.

Related specs

esc

Try , , or .

↑↓ move↵ open