1

I have an issue that's arising from my script process. It utilises code that determines a sloped Moving Average from the 336 day EMA.

ft = input.float(2,title="Filter Top",step=0.1)
fb = input.float(-2,title="Filter Top",step=0.1)
fthigh = input.float(4, title="Filter High Top", step=0.1)
ftlow = input.float(-4, title="Filter Low Top", step=0.1)
src1=input(ohlc4,title="source")
angle(_src1) =>
    rad2degree=180/3.14159265359  //pi 
    ang=rad2degree*math.atan((_src1[0] - _src1[1])/ta.atr(27)) 

ma=ta.ema(src1,input.int(336))
ma_slope=angle(ma)

filter = ma_slope > ft and ma_slope < fthigh ? color.aqua : ma_slope < fb and ma_slope > ftlow ? color.yellow : ma_slope > fthigh ? color.orange : ma_slope < ftlow ? color.green : color.white

The code above simply plots a line on an alternate pane to price window and changes colors depending on the number. (e.g. a slope of 8 indicates price has been bullish for some time, while a slope of -8 indicates price has been bearish for some time and potentially allows me to spot a reversal).

Moving Average Slope

enter image description here

I then found an RSI/Bollinger Band Multi-Timeframe indicator that I wanted to Frankenstein into my strategy however here comes the issue. The entry condition that I want from the RSI/Bollinger indicator is on the 15 minute timeframe, and my strategy runs on the 5 minute time frame.

On top of this, for the script to function as I would like it, I am calling the source for the RSI section of code from ma_slope which is my 'id variable' for the Moving Average Slope code.

It looks something like this:

RSI/BB MTF Indicator

enter image description here

ma(source, length, type) =>
    switch type
        "SMA" => ta.sma(source, length)
        "Bollinger Bands" => ta.sma(source, length)
        "EMA" => ta.ema(source, length)
        "SMMA (RMA)" => ta.rma(source, length)
        "WMA" => ta.wma(source, length)
        "VWMA" => ta.vwma(source, length)


rsiLengthInput = input.int(100, minval=1, title="RSI Length", group="RSI Settings")
rsiSourceInput = ma_slope
maTypeInput = input.string("Bollinger Bands", title="MA Type", options=["SMA", "Bollinger Bands", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group="MA Settings")
maLengthInput = input.int(200, title="MA Length", group="MA Settings")
bbMultInput = input.float(2.0, minval=0.001, maxval=50, title="BB StdDev", group="MA Settings")

up = ta.rma(math.max(ta.change(rsiSourceInput), 0), rsiLengthInput)
down = ta.rma(-math.min(ta.change(rsiSourceInput), 0), rsiLengthInput)
rsi = down == 0 ? 100 : up == 0 ? 0 : 100 - (100 / (1 + up / down))
rsiMA = ma(rsi, maLengthInput, maTypeInput)
isBB = maTypeInput == "Bollinger Bands"
bbLow = rsiMA - ta.stdev(rsi, maLengthInput) * bbMultInput
bbHigh = rsiMA + ta.stdev(rsi, maLengthInput) * bbMultInput

The code above is the raw code transcribed from the RSI/BB Multi TF indicator and I've tried various forms of request.security() in ways such as:

fetchDataOn15MinuteTF(resolution, expression) =>
    request.security(syminfo.tickerid, resolution, expression)

and then following with:

ma(source, length, type) =>
    switch type
        "SMA" => ta.sma(source, length)
        "Bollinger Bands" => ta.sma(source, length)
        "EMA" => ta.ema(source, length)
        "SMMA (RMA)" => ta.rma(source, length)
        "WMA" => ta.wma(source, length)
        "VWMA" => ta.vwma(source, length)

// Define a function that fetches the 15-minute timeframe data
fetchDataOn15MinuteTF(resolution, expression) =>
    request.security(syminfo.tickerid, resolution, expression)

rsiLengthInput = input.int(100, minval=1, title="RSI Length", group="RSI Settings")
rsiSourceInput = ma_slope
maTypeInput = input.string("Bollinger Bands", title="MA Type", options=["SMA", "Bollinger Bands", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group="MA Settings")
maLengthInput = input.int(200, title="MA Length", group="MA Settings")
bbMultInput = input.float(2.0, minval=0.001, maxval=50, title="BB StdDev", group="MA Settings")

rsiSourceInput15 = fetchDataOn15MinuteTF("15", rsiSourceInput)

up = ta.rma(math.max(ta.change(rsiSourceInput15), 0), rsiLengthInput)
down = ta.rma(-math.min(ta.change(rsiSourceInput15), 0), rsiLengthInput)
rsi = down == 0 ? 100 : up == 0 ? 0 : 100 - (100 / (1 + up / down))

rsi15 = fetchDataOn15MinuteTF("15", rsi)

rsiMA = ma(rsi15, maLengthInput, maTypeInput)

bbLow = rsiMA - ta.stdev(rsi15, maLengthInput) * bbMultInput
bbHigh = rsiMA + ta.stdev(rsi15, maLengthInput) * bbMultInput

Or something to that effect, alternating variables every which way but with no luck to change the outcome (invalid entries based on buy_condition2).

My entry is then predicated on the following:

buy_condition2 = (filter == color.yellow) and rsi < bbLow

if buy_condition2
    strategy.entry("Long", strategy.long, qty=10)

So that when the filter in my ma_slope calculation is less than -2 (filter == color.yellow, crude) and RSI goes below the Bollinger Band, it allows for a long condition.

The result in any attempt at requesting higher timeframe data for the RSI/Bollinger Band information coupled with RSI's source being ma_slope is that long positions do not enter when conditions are correct or they enter when positions are incorrect too.

Entry Conditions not being met

enter image description here

Posted in main thread.

EDIT

1.0 I feel I should mention that there is some leeway in entry signals with ma_slope where a buy entry is valid if ma_slope value is between -1.9 and -2.1 so that is not the issue. The Moving Average Slope code is reliable for me in all situations.

James Z
  • 12,209
  • 10
  • 24
  • 44
spenke
  • 11
  • 2

1 Answers1

0

Define your time period that you wish to fetch your data from.

fetchDataOnHigherTF(resolution, expression) => 
    request.security(syminfo.tickerid, resolution, expression)

Your resolution is the timeframe in minutes (e.g. "15" for 15m, "60" for one hour. Your expression is the pre-defined variable in your code. For me, this was "filter".

The code then reads as follows.

fetch15MinFilter = fetchDataOnHigherTF("15", filter)
fetch1HrFilter = fetchDataOnHigherTF("60", filter)

My buy condition is then updated as follows.

buy_condition3 = (prev_color2 == color.yellow) and (filter == color.white) and (fetch15MinFilter == color.yellow)

With the code applied on the 5 minute timeframe, the request.security() function then accesses the 15 minute timeframe data for my "filter" variable and requires that when the 5 minute data is valid, the 15min data must also be valid too for a buy condition to be set.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
spenke
  • 11
  • 2