Indicator · Pine Script v5 · Own pane

F&G Cycle Signal for Backtesting-Trading Engine

by f-cksociety

This indicator calculates a Fear & Greed Index sentiment oscillator and formats its values according to the PineCoders external signal protocol for strategy integration.

View on GitHub

GitHub stars11on the repository
Pine versionv5runs as is
Lines of code286
Settings10inputs
LicenceMPL-2.0
Last update4 years ago20 Sep 2022

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

286 lines of Pine Script v5 from signal-ext/fg-cycle-wip.pine, published under MPL-2.0. Keep the author's credit and licence lines when you reuse it.

fg-cycle-wip.pine
//@version=5
//@author=LucF, for PineCoders

// Signal for Backtesting-Trading Engine [PineCoders]
//  v1.3, 2019.06.21 02:58

// PineCoders, Tools and ideas for all Pine coders.
// This script is referenced from the PineCoders FAQ & Code here: http://www.pinecoders.com/faq_and_code/#how-can-i-use-one-scripts-output-as-an-input-into-another
// Documentation: https://www.tradingview.com/script/y4CvTwRo-Signal-for-Backtesting-Trading-Engine-PineCoders/

// This script is an example of how to configure a signal for the PineCoders Backtesting-Trading Engine
// which you will find here: https://www.tradingview.com/script/dYqL95JB-Backtesting-Trading-Engine-PineCoders/
// We used the built-in MACD indicator as a template. The script's signal adheres to the following protocol:

// EXTERNAL SIGNAL PROTOCOL
//      Only one external indicator can be connected to a script; in order to leverage its use to the fullest,
//      the engine provides options to use it as either and entry signal, an entry/exit signal or a filter.
//      When used as an entry signal, you can also use the signal to provide the entry stop. Here’s how this works.
//        - For filter state: supply +1.0 for bull (long entries allowed), -1.0 for bear (short entries allowed).
//        - For entry signals: supply +2.0 for long, -2.0 for short.
//        - For exit signals: supply +3.0 for exit from long, -3.0 for exit from short.
//        - To send an entry stop level with entry signal: Send positive stop level for long entry
//          (e.g. 103.33 to enter a long with a stop at 103.33), negative stop level for short entry
//          (e.g. -103.33 to enter a short with a stop at 103.33). If you use this feature,
//          your indicator will have to check for exact stop levels of 1.0, 2.0 or 3.0 and their negative counterparts,
//          and fudge them with a tick in order to avoid confusion with other signals in the protocol.
//      Note that each use must be confirmed in the corresponding section of the script's Settings/Inputs.

// CONFIGURATION OF ALERTS
//      Entry and Event alerts will generally be configured to trigger Once Per Bar Close.
//      Exit alerts can be configured to trigger Once Per Bar Close or Once Per Bar, depending on how fast
//      you want them. Once Per Bar means the alert will trigger the moment the condition is first encountered
//      during the realtime bar, instead of at the bar's close.
//      Entry and Exit alerts trigger at the same bar where the relevant marker will appear on the chart.
//      Event alerts trigger on the bar following the appearance of their respective marker on the chart.

// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
//# *
//# * Study       : Trading Psychology - Fear & Greed Index by DGT
//# * Author      : © dgtrd
//# *
//# * Revision History
//# *  Release    : Jul 21, 2020
//# *  Update     : Apr 09, 2021 : Added ability to display Current Time Frame's Fear and Greed Index
//# *  Update     : Apr 09, 2022 : Added Price Candle display option with Fear & Greed weighted risk levels 
//# *
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
indicator('F&G CYCLE ʙʏ DGT Signal for Backtesting-Trading Engine [PineCoders]')

// Allow selection of signal content.
IncludeFilter = input(true, 'Include Filter')
IncludeEntries = input(true, 'Include Entries')
IncludeStops = input(true, 'Include Stops with Entries')
IncludeExits = input(true, 'Include Exits')


// -Inputs ====================================================================================== //

display = input.string('Fear & Greed Index', 'Display as', options=['Price Candles', 'Fear & Greed Index'])
smoothLength = input.int(5, 'RMA Smoothing Length', minval=1, maxval=13)
faster = input(false, 'Fear & Greed Index : Calculation with Faster Legths')
daily = input(false, 'Display Daily Time Frame Calculated Value')
lagendDesc = input(true, 'Show Color Legend')
hLabel = input(false, 'Hide Statistical Label')


fastLength = faster ? 13 : 21
slowLength = faster ? 89 : 144

// -Calculations ================================================================================ //

pmacd = (close / ta.ema(close, slowLength) - 1) * 100
pmacd_d = request.security(syminfo.tickerid, 'D', pmacd, barmerge.gaps_off, barmerge.lookahead_on)

ror = (close - close[slowLength]) / close[slowLength] * 100
ror_d = request.security(syminfo.tickerid, 'D', ror, barmerge.gaps_off, barmerge.lookahead_on)

accDist = close == high and close == low or high == low ? 0 : (2 * close - low - high) / (high - low)
nzVolume = nz(volume)
moneyFlow = math.sum(accDist * nzVolume, fastLength) / math.sum(nzVolume, fastLength) * 100

accDist_d = request.security(syminfo.tickerid, 'D', accDist, barmerge.gaps_off, barmerge.lookahead_on)
nzVolume_d = request.security(syminfo.tickerid, 'D', nzVolume)
moneyFlow_d = math.sum(accDist_d * nzVolume_d, fastLength) / math.sum(nzVolume_d, fastLength) * 100

vix = request.security('VIX', timeframe.period, -(close / ta.ema(close, slowLength) - 1) * 100, barmerge.gaps_off, barmerge.lookahead_on)
vix_d = request.security('VIX', 'D', -(close / ta.ema(close, slowLength) - 1) * 100, barmerge.gaps_off, barmerge.lookahead_on)

gold = request.security('GOLD', timeframe.period, -(1 - close[fastLength] / close) * 100, barmerge.gaps_off, barmerge.lookahead_on)
gold_d = request.security('GOLD', 'D', -(1 - close[fastLength] / close) * 100, barmerge.gaps_off, barmerge.lookahead_on)

cycle_raw = nzVolume ? math.avg(pmacd, ror, moneyFlow, vix, gold) : math.avg(pmacd, ror, vix, gold)
cycle_raw_d = nzVolume_d ? math.avg(pmacd_d, ror_d, moneyFlow_d, vix_d, gold_d) : math.avg(pmacd_d, ror_d, vix_d, gold_d)

cycle = ta.rma(cycle_raw, smoothLength)
cycle_d = ta.rma(cycle_raw_d, smoothLength)

f_getText(_cycle) =>
    if _cycle > 73
        'Extreame Greed'
    else if _cycle > 33
        'Greed'
    else if _cycle < -15
        'Fear'
    else if _cycle < -41
        'Extreame Fear'
    else
        'Neutral'

f_getColor(_cycle) =>
    if _cycle >= 73
        #006400
    else if _cycle >= 63 and _cycle < 73
        #007439
    else if _cycle >= 52 and _cycle < 63
        #008368
    else if _cycle >= 41 and _cycle < 52
        #009096
    else if _cycle >= 30 and _cycle < 41
        #009bbf
    else if _cycle >= 20 and _cycle < 30
        #00a4df
    else if _cycle >= 10 and _cycle < 20
        #00a4df
    else if _cycle >= 5 and _cycle < 10
        #65a095
    else if _cycle < -5 and _cycle >= -10
        #b7b763
    else if _cycle < -10 and _cycle >= -15
        #fafa6e
    else if _cycle < -15 and _cycle >= -20
        #fecb35
    else if _cycle < -20 and _cycle >= -25
        #ff9800
    else if _cycle < -25 and _cycle >= -31
        #ff7434
    else if _cycle < -31 and _cycle >= -37
        #ff5252
    else if _cycle < -37 and _cycle >= -41
        #c72e29
    else if _cycle < -41
        #910000
    else
        #92928f

f_getColor1(_cycle) =>
    if _cycle >= 73
        #910000
    else if _cycle >= 63 and _cycle  <  73
        #c72e29
    else if _cycle >= 52 and _cycle  <  63
        #ff5252
    else if _cycle >= 41 and _cycle  <  52
        #ff7434
    else if _cycle >= 30 and _cycle  <  41
        #ff9800
    else if _cycle >= 20 and _cycle  <  30
        #fecb35
    else if _cycle >= 10 and _cycle  <  20
        #fafa6e
    else if _cycle >= 5  and _cycle  <  10
        #b7b763
    else if _cycle < -5  and _cycle >= -10
        #65a095
    else if _cycle < -10 and _cycle >= -15
        #00a4df
    else if _cycle < -15 and _cycle >= -20
        #00a4df
    else if _cycle < -20 and _cycle >= -25
        #009bbf
    else if _cycle < -25 and _cycle >= -31
        #009096
    else if _cycle < -31 and _cycle >= -37
        #008368
    else if _cycle < -37 and _cycle >= -41
        #007439
    else if _cycle < -41 
        #006400
    else
        #92928f

// -Plotting ==================================================================================== //

fgColor = daily ? f_getColor(cycle_d) : f_getColor(cycle)
plot(display == 'Fear & Greed Index' ? daily ? cycle_d : cycle : na, 'Psychology of The Market Cycle - Index Display', fgColor, 2)

var label fgiLabel = na
if not hLabel
    fgiLabel := label.new(time + math.round(ta.change(time) * 7), display == 'Price Candles' ? close : daily ? cycle_d : cycle, (daily ? '*Daily' : 'Daily') + ' Time Frame : ' + f_getText(cycle_d) + ' : ' + 
                             str.tostring(math.round(cycle_d, 2)) + '%\n' + (daily ? 'Current' : '*Current') + ' Time Frame (' + timeframe.period + ') : ' + f_getText(cycle) + ' : ' + 
                             str.tostring(math.round(cycle, 2)) + '%', xloc.bar_time, tooltip='Psychology of The Market Cycle by DGT\n\n' + 'Fear & Greed Index :\nDaily Time Frame : ' + f_getText(cycle_d) + ' : ' + 
                             str.tostring(math.round(cycle_d, 2)) + '%\nCurrent Time Frame (' + timeframe.period + ') : ' + f_getText(cycle) + ' : ' + 
                             str.tostring(math.round(cycle, 2)) + '%' + '%\n\nReference Sources : ' + '\n-------------------------------------------------------------------' + 
                             '\n 1 - Price Convergence/Divergence to/from its Moving Average (' + str.tostring(slowLength) + ') :\n     Daily TF ' + str.tostring(math.round(pmacd_d, 2)) + '% / Current TF ' + str.tostring(math.round(pmacd, 2)) + '%' + 
                             '\n 2 - Rate of Return (Momentum/RoC), Length (' + str.tostring(slowLength) + ') :\n     Daily TF ' + str.tostring(math.round(ror_d, 2)) + '% / Current TF ' + str.tostring(math.round(ror, 2)) + '%' + 
                             '\n 3 - Chaikin Money Flow, Length (' + str.tostring(fastLength) + ') :\n     Daily TF ' + str.tostring(math.round(moneyFlow_d, 2)) + '% / Current TF ' + str.tostring(math.round(moneyFlow, 2)) + '% \n      ps: cmf calculated only if volume data is provided' + 
                             '\n 4 - VIX - Volatility (Fear) Index, Length (' + str.tostring(slowLength) + ') :\n     Daily TF ' + str.tostring(math.round(vix_d, 2)) + '% / Current TF ' + str.tostring(math.round(vix, 2)) + '%' + 
                             '\n 5 - Safe Haven Demand - Gold Demand, Length (' + str.tostring(fastLength) + ') :\n     Daily TF ' + str.tostring(math.round(gold_d, 2)) + '% / Current TF ' + str.tostring(math.round(gold, 2)) + '%' + 
                             '\n\nWarren Buffett’s quote, buy when others are fearful, and sell when others are greedy', color=color.new(color.gray, 85), style=label.style_label_left, textcolor=color.gray, textalign=text.align_left)

label.delete(fgiLabel[1])

var o = 0., var h = 0., var l = 0., var c = 0.

if display == 'Price Candles'
    o := open, h := high, l := low, c := close

fgColor := daily ? f_getColor1(cycle_d) : f_getColor1(cycle)

if display == 'Fear & Greed Index'
    fgColor := na

plotcandle(o, h, l, c, 'Psychology of The Market Cycle - Price Display', fgColor, fgColor, bordercolor = fgColor)

var table logo = table.new(position.bottom_right, 1, 1)
table.cell(logo, 0, 0, "☼☾  ", text_size = size.normal, text_color = color.teal)


var table legend = table.new(position.middle_right   , 1, 5)

if lagendDesc
    if display == 'Price Candles'
        table.cell(legend, 0, 0, "Max Opportunity █", text_size = size.small, text_color = #006400, text_halign = text.align_right)
        table.cell(legend, 0, 1, "Opportunity █", text_size = size.small, text_color = #008368, text_halign = text.align_right)
        table.cell(legend, 0, 2, "Neutral █", text_size = size.small, text_color = #92928f, text_halign = text.align_right)
        table.cell(legend, 0, 3, "Risk █", text_size = size.small, text_color = #ff7434, text_halign = text.align_right)
        table.cell(legend, 0, 4, "Max Rsik █", text_size = size.small, text_color = #910000, text_halign = text.align_right)
    else
        table.cell(legend, 0, 0, "Extreame Greed █", text_size = size.small, text_color = #006400, text_halign = text.align_right)
        table.cell(legend, 0, 1, "Greed █", text_size = size.small, text_color = #008368, text_halign = text.align_right)
        table.cell(legend, 0, 2, "Neutral █", text_size = size.small, text_color = #92928f, text_halign = text.align_right)
        table.cell(legend, 0, 3, "Fear █", text_size = size.small, text_color = #ff7434, text_halign = text.align_right)
        table.cell(legend, 0, 4, "Extreame Fear █", text_size = size.small, text_color = #910000, text_halign = text.align_right)


// ————— Filter.
FilterLong = Fear
FilterShort = Greed

// ————— Entries.
EnterLong = Fear
EnterShort = Greed

// ————— Stops.
Atr = ta.atr(14)
StopLong = math.min(ta.lowest(5), math.min(close, open) - Atr * 1.5)
StopShort = math.max(ta.highest(5), math.max(close, open) + Atr * 1.5)

// ————— Exits.
ExitLong = Neutral
ExitShort = Neutral

// ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲
// ——————————————————————————————————————————————————————————————————————————————————————


// ————— This function ensures that no stop value equal to one of the protocol's reserved values is sent, so it isn't misinterpreted as a signal.
// The fudge is in the direction where the trade's risk is decreased by a tick, so added for longs and subtracted for shorts.
FudgeStop(_stop, _fudgedir) =>
    _stop == 1.0 or _stop == 2.0 or _stop == 3.0 ? _stop + syminfo.mintick * _fudgedir : _stop

// ————— Build required values corresponding to states.
Filter = FilterLong ? 1 : FilterShort ? -1 : 0
Entries = EnterLong ? 2 : EnterShort ? -2 : 0
FudgeStop__1 = FudgeStop(StopLong, 1)
FudgeStop__2 = FudgeStop(StopShort, -1)
Stops = EnterLong ? FudgeStop__1 : EnterShort ? -FudgeStop__2 : 0
Exits = ExitLong ? 3 : ExitShort ? -3 : 0

// ————— We must decide which value will be sent in case more than one is different than 0, since only one value can be sent at each bar.
// Priority is given to exits, with filter states coming last.
Signal = IncludeExits and Exits != 0 ? Exits : IncludeStops and Stops != 0 ? Stops : IncludeEntries and Entries != 0 ? Entries : IncludeFilter and Filter != 0 ? Filter : na

// ————— Plot signal which is to be connected to the Engine through the External Indicator field at the very bottom of the Engine's Settings/Inputs.
plot(Signal, 'Signal')


// ————— Plots markers.
plotshape(IncludeEntries and EnterLong, 'Enter Long', style=shape.triangleup, location=location.bottom, color=color.new(color.green, 0), size=size.small, text='Enter\nLong')
plotshape(IncludeEntries and EnterShort, 'Enter Short', style=shape.triangledown, location=location.top, color=color.new(color.red, 0), size=size.small, text='Enter\nShort')
plotshape(IncludeExits and ExitLong, 'Exit Long', style=shape.triangledown, location=location.top, color=color.new(color.green, 0), size=size.tiny, text='Exit\nLong')
plotshape(IncludeExits and ExitShort, 'Exit Short', style=shape.triangleup, location=location.bottom, color=color.new(color.red, 0), size=size.tiny, text='Exit\nShort')

bgcolor(color=IncludeFilter and FilterLong ? color.new(#00FF00,93) : IncludeFilter and FilterShort ? color.new(#FF0000,90) : na, title='Filter Background')

Overview

F&G Cycle Signal for Backtesting-Trading Engine outputs protocol-compliant numerical values (+1/-1 for filters, +2/-2 for entries, +3/-3 for exits) and optional stop loss levels plotted in a separate pane. User settings control calculation speed, RMA smoothing length, daily timeframe calculations, and toggles for filter, entry, stop, and exit conditions.

Details

Published by

f-cksociety on GitHub

Type

Indicator, Pine Script v5

Draws

Separate pane below the chart

Category

Oscillators & momentum

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Include FilterbooltrueIncludeFilter
Include EntriesbooltrueIncludeEntries
Include Stops with EntriesbooltrueIncludeStops
Include ExitsbooltrueIncludeExits
Display asstringFear & Greed Indexdisplay
RMA Smoothing Lengthint5smoothLength
Fear & Greed Index : Calculation with Faster Legthsboolfalsefaster
Display Daily Time Frame Calculated Valueboolfalsedaily
Show Color LegendbooltruelagendDesc
Hide Statistical LabelboolfalsehLabel
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

Asymmetrical RSI

by everget
948 stars

Asymmetrical RSI is an indicator that computes a custom relative strength index from the rate of change of a user-selected source. It plots the resulting ARSI line in a separate pane with color coding that turns green above the overbought level and red below t

Indicator v4 Oscillators & momentum
Updated 10 days ago · GPL-3.0 GitHub repository of Asymmetrical RSI

This indicator calculates momentum setups based on the Relative Strength Index (RSI) and plots in a separate pane. It offers multiple scanning modes such as Continuous Break, Continuous Retracement, Flip Break, Flip Retracement, and both regular and hidden div

Indicator v6 Oscillators & momentumDivergence Repaints
Updated 1 year ago · MPL-2.0 GitHub repository of Momentum Setup - RSI Directional Momentum Indicator

Beep Boop

by magic8bot
409 stars

This indicator calculates a modified MACD oscillator and signal line alongside a trend EMA filter, plotting the output as a stylized column histogram in a separate pane. Instead of plotting true MACD distance, it quantifies positive and negative histogram mome

Indicator v4 Oscillators & momentumTrend
Updated 3 years ago · MIT GitHub repository of Beep Boop
261 stars

This indicator demonstrates an experimental graph-style scatter visualization within a separate pane using Pine Script arrays. It tracks two features across recent bars: the single-bar price change and a scaled 14-period Relative Strength Index. Values are loa

Indicator v4 Oscillators & momentum
Updated 4 years ago · None stated GitHub repository of Example: Graph Style - 4th Dimension RSI

KD指標

by TaichiS
219 stars

This script calculates and plots a Stochastic Oscillator (KD indicator) in a separate chart pane. It determines the fast stochastic value over a 9-period lookback, then applies a 3-period Simple Moving Average (SMA) to create the %K line, and a second 3-period

Indicator v4 Oscillators & momentum
Updated 5 years ago · None stated GitHub repository of KD指標

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers