Kewl ! Logistic Oscillators indicator.
Code: Select all
//@version=6
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
//# *
//# * Study : Logistic Map Application on RSI, STOCH, ROC, AO, and Custom Logistic Interpretation
//# * Author : © dgtrd
//# *
//# * Revision History
//# * Release : Nov 5 , 2020 : Initial Release
//# * Update : Nov 21, 2020 : Backtest Framework Adaptation
//# * Update : Mar 13, 2021 : Enchanced Backtest Framework
//# * - long/short/stoploss conditions enchaced
//# * - early warning ability added (label + alert)
//# * Update : Mar 16, 2021 : Alert additions to Logistic and Backtest Framework
//# *
//# *
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
indicator('Logistic RSI, STOCH, ROC, AO, ... by DGT', 'LOGISTIC ☼☾', max_labels_count = 500) //, resolution="")
// -Inputs ══════════════════════════════════════════════════════════════════════════════════════ //
display = display.all - display.status_line
ti = input.string('Logistic Dominance', 'Select Indicator', display = display,
options = ['Awesome Oscillator (AO)', 'Logistic Dominance', 'Rate of Change (ROC)', 'Relative Strength Index (RSI)', 'Stochastic (STOCH)'],
tooltip = 'Select the base oscillator used as the input for the Logistic Map transformation.\n\n' +
'Available sources:\n' +
'• AO – momentum derived from Awesome Oscillator\n' +
'• Logistic Dominance – custom price-based dominance metric\n' +
'• ROC – Rate of Change momentum\n' +
'• RSI – Relative Strength Index\n' +
'• STOCH – Stochastic oscillator\n\n' +
'The selected oscillator is transformed through a Logistic Map iteration process to highlight nonlinear momentum dynamics.')
source = input.source(close, 'Source', group = 'Logistic Settings', display = display)
length = input.int(13, 'Logistic Map Length', minval = 1, group = 'Logistic Settings', display = display,
tooltip = 'Lookback period used when normalizing the input signal before applying the Logistic Map transformation.\n\n' +
'• Higher values → smoother and more stable behavior\n' +
'• Lower values → more reactive but noisier output\n\n' +
'Controls how sensitive the chaotic iterations are to short-term price changes.')
lenLD = input.int(5, 'Length : Logistic Dominance', minval = 1, group = 'Optimization / Customization Metrics', display = display,
tooltip = 'Lookback period used when the Logistic Dominance mode is selected as the base oscillator.\n\n' +
'Controls how price dominance and directional pressure are measured before the Logistic Map transformation.')
lenROC = input.int(9, 'Length : Rate of Change (ROC)', minval = 1, group = 'Optimization / Customization Metrics', display = display,
tooltip = 'Lookback period used for the Rate of Change oscillator.\n\n' +
'Only applied when ROC is selected as the base indicator.\n\n' +
'Higher values emphasize broader momentum trends, while lower values respond faster to short-term moves.')
lenRSI = input.int(14, 'Length : Relative Strength Index (RSI)', minval = 1, group = 'Optimization / Customization Metrics', display = display,
tooltip = 'Lookback period used for the RSI calculation.\n\n' +
'Only affects the indicator when RSI is selected as the base oscillator for the Logistic Map.')
lenSTO = input.int(14, 'Length : Stochastic (STOCH)', minval = 1, group = 'Optimization / Customization Metrics', display = display,
tooltip = 'Lookback period used for the Stochastic oscillator.\n\n' +
'Only applied when STOCH is selected in the "Select Indicator" setting.')
style = input.string('Cross', 'Style', group = 'Display Settings', display = display,
options = ['Cross', 'Line', 'StepLine'],
tooltip = 'Visualization style for the Logistic Map iterations.\n\n' +
'• Cross → discrete markers for each iteration\n' +
'• Line → continuous line connecting iterations\n' +
'• StepLine → stepped representation emphasizing\n' +
' discrete iteration levels.')
uC = input.color(color.teal, 'Colors : Bullish', inline = 'PLOT', group = 'Display Settings')
dC = input.color(color.red, 'Bearish', inline = 'PLOT', group = 'Display Settings')
d = input.bool(false, 'Standard Deviation Line Alone', group = 'Display Settings',
tooltip = 'Display only the aggregated standard deviation\n' +
'of all Logistic Map iterations.\n\n' +
'• ON → hides individual iterations and shows\n' +
' only the summarized volatility/momentum signal\n' +
'• OFF → displays all Logistic Map iterations.')
// -Calculations ════════════════════════════════════════════════════════════════════════════════ //
f_logmap(_s, _r, _l) =>
_r * _s / ta.highest(_l) * (1 - _s / ta.highest(_l))
f_map(_s, _r, _v) =>
mapeq = f_logmap(_s, _r, length)
lmap = mapeq
for i = 0 to 29 by 1
array.push(_v, lmap)
lmap := _r * math.abs(mapeq[i]) * (1 - mapeq[i])
lmap
lmap
r = if ti == 'Awesome Oscillator (AO)'
ta.sma(hl2, 5) / ta.sma(hl2, 34) - 1
else if ti == 'Logistic Dominance'
-f_logmap(-source, ta.change(source, lenLD) / source[lenLD], lenLD) - f_logmap(source, ta.change(source, lenLD) / source[lenLD], lenLD)
else if ti == 'Rate of Change (ROC)'
ta.change(source, lenROC) / source[lenROC]
else if ti == 'Relative Strength Index (RSI)'
ta.rsi(source, lenRSI) / 100 - .5
else if ti == 'Stochastic (STOCH)'
ta.stoch(source, high, low, lenSTO) / 100 - .5
var v = array.new_float(0)
val = f_map(source, r, v)
s = style == 'Cross' ? plot.style_cross : style == 'Line' ? plot.style_line : plot.style_stepline
// -Plotting ════════════════════════════════════════════════════════════════════════════════════ //
plot(d ? na : val, 'Last Iteration', val >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 1), '2nd Iteration', array.get(v, 1) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 2), '3rd Iteration', array.get(v, 2) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 3), '4th Iteration', array.get(v, 3) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 4), '5th Iteration', array.get(v, 4) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 5), '6th Iteration', array.get(v, 5) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 6), '7th Iteration', array.get(v, 6) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 7), '8th Iteration', array.get(v, 7) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 8), '9th Iteration', array.get(v, 8) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 9), '10th Iteration', array.get(v, 9) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 10), '11th Iteration', array.get(v, 10) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 11), '12th Iteration', array.get(v, 11) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 12), '13th Iteration', array.get(v, 12) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 13), '14th Iteration', array.get(v, 13) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 14), '15th Iteration', array.get(v, 14) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 15), '16th Iteration', array.get(v, 15) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 16), '17th Iteration', array.get(v, 16) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 17), '18th Iteration', array.get(v, 17) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 18), '19th Iteration', array.get(v, 18) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 19), '20th Iteration', array.get(v, 19) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 20), '21st Iteration', array.get(v, 20) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 21), '22nd Iteration', array.get(v, 21) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 22), '23rd Iteration', array.get(v, 22) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 23), '24th Iteration', array.get(v, 23) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 24), '25th Iteration', array.get(v, 24) >= 0 ? uC : dC, 1, s, display = display)
//plot(d ? na : array.get(v, 25), '26th Iteration', array.get(v, 25) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 26), '27th Iteration', array.get(v, 26) >= 0 ? uC : dC, 1, s, display = display)
//plot(d ? na : array.get(v,27), "28th Iteration", array.get(v,27) >= 0 ? uC : dC, 1, s, display = display)
plot(d ? na : array.get(v, 28), '29th Iteration', array.get(v, 28) >= 0 ? uC : dC, 1, s, display = display)
//plot(d ? na : array.get(v,29), "30th Iteration", array.get(v,29) >= 0 ? uC : dC, 1, s, display = display)
array.remove(v, 0)
aStDev = math.sign(array.avg(v)) * array.stdev(v)
plot(aStDev, 'Standard Deviation of Array\'s Elements', array.avg(v) >= 0 ? #26c6da : #ffa726, 2, display = display)
array.clear(v)
// -Alerts ══════════════════════════════════════════════════════════════════════════════════════ //
longAlertCondition = ta.crossover(aStDev, 0)
alertcondition(longAlertCondition, 'Long : Early Warning', 'LOGISTIC - Not Confirmed Probable Long Trade Opportunity\n{{exchange}}:{{ticker}}->\nPrice = {{close}},\nTime = {{time}}')
alertcondition(longAlertCondition[1], 'Long : Trading Opportunity', 'LOGISTIC - Probable Long Trade Opportunity\n{{exchange}}:{{ticker}}->\nPrice = {{close}},\nTime = {{time}}')
shortAlertCondition = ta.crossunder(aStDev, 0)
alertcondition(shortAlertCondition, 'Short : Early Warning', 'LOGISTIC - Not Confirmed Probable Short Trade Opportunity\n{{exchange}}:{{ticker}}->\nPrice = {{close}},\nTime = {{time}}')
alertcondition(shortAlertCondition[1], 'Short : Trading Opportunity', 'LOGISTIC - Probable Short Trade Opportunity\n{{exchange}}:{{ticker}}->\nPrice = {{close}},\nTime = {{time}}')
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
//# *
//# * Study : Backtest Framework
//# * Author : © dgtrd
//# * Purpose : Trade simulation with long, short and reverse trade ability
//# *
//# * Revision History
//# * Release : Nov 21, 2020 : Initial Release
//# * Update : Mar 13, 2021 : Enhanced framework — long/short/stoploss, early warning
//# * Update : Apr 03, 2026 : Short trade support, trade mode selector (Long / Short / Both),
//# * reverse on signal, intrabar stop loss, redesigned stats label
//# *
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
bt_yAnchor = close
// ── Inputs ───────────────────────────────────────────────────────────────────── //
btGR = '============= Backtest Framework ============='
isBackTest = input.bool(false, 'Enable Backtest', group = btGR,
tooltip = 'Enable or disable the backtest framework.\n' +
'• ON → trades simulated using the rules below\n' +
'• OFF → only live signals shown')
tradeMode = input.string('Both', 'Trade Mode', options = ['Long Only', 'Short Only', 'Both'], group = btGR, display = display,
tooltip = 'Defines which trade directions are simulated.\n\n' +
'• Long Only — enters on long signal, exits on short signal or stop loss\n' +
'• Short Only — enters on short signal, exits on long signal or stop loss\n' +
'• Both — enters on either signal, optionally reverses on the opposite')
reverseOnSignal = input.bool(true, 'Reverse on Opposite Signal', group = btGR,
tooltip = 'Only applies when Trade Mode is Both.\n' +
'When enabled, an opposite signal immediately closes the current trade\n' +
'and opens a new one in the other direction — always in trade once started.\n' +
'When disabled, opposite signal exits only — no new trade until next entry signal.')
dasCapital = input.float(1000., 'Initial Capital', group = btGR, display = display,
tooltip = 'Starting capital for the simulation.\n' +
'Used to calculate compounding PnL and final equity.')
lenBckTst = input.float(1., 'Period (Years)', minval = 0., step = .1, group = btGR, display = display,
tooltip = 'Lookback window for the simulation in years.\n' +
'Capped automatically if the selected timeframe has insufficient history.')
isStopLoss = input.bool(false, 'Apply Stop Loss', inline = 'sl', group = btGR,
tooltip = 'Exits the trade if price moves against the position intrabar.\n' +
'Long SL : low reaches entry × (1 − %)\n' +
'Short SL: high reaches entry × (1 + %)')
stopLoss = input.float(1., ' %', step = .1, minval = 0., inline = 'sl', group = btGR, display = display) / 100
useCandleL = input.bool(false, 'Long Candle Confirmation', group = btGR,
tooltip = 'Long entries only taken on bullish bars (close > open).')
useCandleS = input.bool(false, 'Short Candle Confirmation', group = btGR,
tooltip = 'Short entries only taken on bearish bars (close < open).')
isSudden = input.bool(true, 'Avoid Same-Bar Conflicts', group = btGR,
tooltip = 'Skips entries when both long and short signals fire on the same bar.\n' +
'Reduces false entries from volatile spikes.')
isTest = input.bool(false, '❗ Next Bar Mode (Repaints)', group = btGR,
tooltip = 'Uses the next bar\'s open for simulation instead of the confirmed bar open.\n' +
'Produces earlier entries but signals will repaint.\n' +
'For testing and comparison only — do not use for live alerts.')
lblInOutSL = input.bool(true, 'Show Entry / Exit Labels', group = btGR,
tooltip = 'Displays L / S / SL / TP labels at entry and exit bars with tooltips showing direction, price, change, and capital.')
lblWarnings = input.bool(true, 'Show Early Warnings', group = btGR,
tooltip = 'Shows a ⚠️ label when a signal fires but has not yet been confirmed.\n' +
'Label is deleted on the following bar regardless of outcome.')
lblTrdStat = input.bool(true, 'Show Trade Statistics', group = btGR,
tooltip = 'Displays a floating label with full trade summary.\n' +
'Includes win rate, PnL, long/short breakdown, and current trade status.')
// ── Backtest period ──────────────────────────────────────────────────────────── //
startBckTst = time > timenow - lenBckTst * 31556952000
var _dir = array.new_int (1, 0)
var _entry = array.new_float(1, 0.)
var _exit = array.new_float(1, 0.)
var _cap = array.new_float(1, dasCapital)
var _trades = array.new_int (1, 0)
var _winL = array.new_int (1, 0)
var _lossL = array.new_int (1, 0)
var _winS = array.new_int (1, 0)
var _lossS = array.new_int (1, 0)
bt_dir () => array.get(_dir, 0)
bt_entry () => array.get(_entry, 0)
bt_exit () => array.get(_exit, 0)
bt_cap () => array.get(_cap, 0)
bt_trades () => array.get(_trades, 0)
bt_winL () => array.get(_winL, 0)
bt_lossL () => array.get(_lossL, 0)
bt_winS () => array.get(_winS, 0)
bt_lossS () => array.get(_lossS, 0)
f_open(_d, _lbl) =>
array.set(_entry, 0, open)
array.set(_dir, 0, _d)
array.set(_trades, 0, bt_trades() + 1)
if _lbl
label.new(bar_index, _d == 1 ? low : high, text = _d == 1 ? 'L' : 'S',
tooltip = 'Direction .... : ' + (_d == 1 ? 'Long' : 'Short') + '\n' +
'Entry price .. : ' + str.tostring(open) + '\n' +
'Capital ...... : ' + str.tostring(bt_cap(), '#.##'),
style = _d == 1 ? label.style_label_up : label.style_label_down, color = _d == 1 ? color.teal : color.red,
textcolor = color.white, size = size.tiny, force_overlay = true)
f_close(_isSL, _lbl) =>
_d = bt_dir()
_ep = bt_entry()
_xp = _isSL ? close : open
array.set(_exit, 0, _xp)
_entrySafe = math.max(_ep, syminfo.mintick)
_exitSafe = math.max(_xp, syminfo.mintick)
_pnl = _d == 1
? _exitSafe / _entrySafe
: _entrySafe / _exitSafe
_newCap = bt_cap() * _pnl
_profit = _pnl > 1.
array.set(_cap, 0, _newCap)
if _d == 1
array.set(_winL, 0, bt_winL() + (_profit ? 1 : 0))
array.set(_lossL, 0, bt_lossL() + (_profit ? 0 : 1))
else
array.set(_winS, 0, bt_winS() + (_profit ? 1 : 0))
array.set(_lossS, 0, bt_lossS() + (_profit ? 0 : 1))
if _lbl
label.new(bar_index, _d == 1 ? high : low, text = _isSL ? 'SL' : 'TP',
tooltip = 'Exit type .... : ' + (_isSL ? 'Stop Loss' : 'Take Profit') + '\n' +
'Direction .... : ' + (_d == 1 ? 'Long' : 'Short') + '\n' +
'Entry / Exit . : ' + str.tostring(_ep) + ' / ' + str.tostring(_xp) + '\n' +
'Change ....... : ' + str.tostring((_pnl - 1) * 100, '#.##') + '%\n' +
'Capital ...... : ' + str.tostring(_newCap, '#.##'),
style = _d == 1 ? label.style_label_down : label.style_label_up, color = _profit ? color.teal : color.red,
textcolor = color.white, size = size.tiny, force_overlay = true)
array.set(_dir, 0, 0)
if isBackTest
sigL = isTest ? longAlertCondition[1] : longAlertCondition[2]
sigS = isTest ? shortAlertCondition[1] : shortAlertCondition[2]
candleRef = isTest ? 0 : 1
conflict = longAlertCondition[candleRef] and shortAlertCondition[candleRef]
okL = (not useCandleL or close[candleRef] > open[candleRef]) and (not isSudden or not conflict)
okS = (not useCandleS or close[candleRef] < open[candleRef]) and (not isSudden or not conflict)
longCond = sigL and okL
shortCond = sigS and okS
canLong = tradeMode != 'Short Only'
canShort = tradeMode != 'Long Only'
slL = isStopLoss and bt_dir() == 1 and low <= bt_entry() * (1 - stopLoss)
slS = isStopLoss and bt_dir() == -1 and high >= bt_entry() * (1 + stopLoss)
slHit = slL or slS
if startBckTst
var bool _reversed = false
_reversed := false
if reverseOnSignal and tradeMode == 'Both'
if bt_dir() == 1 and shortCond
f_close(false, lblInOutSL)
if canShort
f_open(-1, lblInOutSL)
_reversed := true
else if bt_dir() == -1 and longCond
f_close(false, lblInOutSL)
if canLong
f_open(1, lblInOutSL)
_reversed := true
if not _reversed
exitL = bt_dir() == 1 and (shortCond or slHit)
exitS = bt_dir() == -1 and (longCond or slHit)
if exitL or exitS
f_close(slHit, lblInOutSL)
if bt_dir() == 0
if longCond and canLong
f_open(1, lblInOutSL)
alert('Long entry — ' + syminfo.tickerid + ' | Price: ' + str.tostring(close), alert.freq_once_per_bar)
if shortCond and canShort
f_open(-1, lblInOutSL)
alert('Short entry — ' + syminfo.tickerid + ' | Price: ' + str.tostring(close), alert.freq_once_per_bar)
if slHit
alert('Stop loss — ' + syminfo.tickerid + ' | Price: ' + str.tostring(close), alert.freq_once_per_bar)
var label wLabel = na
if lblWarnings
if canLong and bt_dir() != 1 and longAlertCondition[1] and not shortAlertCondition
wLabel := label.new(bar_index, low, '⚠️',
tooltip = 'Probable long entry — awaiting confirmation\n' +
'If confirmed, trade executes at next bar open.',
color = color.teal, style = label.style_none, textcolor = color.white, size = size.large, force_overlay = true)
label.delete(wLabel[1])
alert('Long early warning — ' + syminfo.tickerid + ' | Price: ' + str.tostring(close), alert.freq_once_per_bar)
if canShort and bt_dir() != -1 and shortAlertCondition[1] and not longAlertCondition
wLabel := label.new(bar_index, high, '⚠️',
tooltip = 'Probable short entry — awaiting confirmation\n' +
'If confirmed, trade executes at next bar open.',
color = color.red, style = label.style_none, textcolor = color.white, size = size.large, force_overlay = true)
label.delete(wLabel[1])
alert('Short early warning — ' + syminfo.tickerid + ' | Price: ' + str.tostring(close), alert.freq_once_per_bar)
if bool(ta.change(time))
label.delete(wLabel[1])
if lblTrdStat
var float years = (timenow - time) / 31556952000
var string perTxt = ''
var label statLbl = na
totalTrades = bt_trades()
totalWin = bt_winL() + bt_winS()
totalLoss = bt_lossL() + bt_lossS()
estimated =
bt_dir() == 1 ? bt_cap() * (close / bt_entry()) :
bt_dir() == -1 ? bt_cap() * (bt_entry() / close) :
bt_cap()
winRate = totalTrades > 0 ? totalWin / totalTrades * 100 : 0.
gainPct = (estimated / dasCapital - 1) * 100
tradeDirTxt = bt_dir() == 1 ? 'Long' :
bt_dir() == -1 ? 'Short' : 'Flat'
if years < lenBckTst
perTxt := str.tostring(lenBckTst, '#.##') + ' Yrs *** (' + str.tostring(bar_index) + ' bars max)'
else
perTxt := str.tostring(lenBckTst, '#.##') + ' Year(s)'
_slTxt = isStopLoss ?
str.tostring(stopLoss * 100, '#.#') + '% — level: ' +
str.tostring(
bt_dir() == 1 ? bt_entry() * (1 - stopLoss) :
bt_dir() == -1 ? bt_entry() * (1 + stopLoss) : 0., '#.##')
: 'Off'
_sep = '\n═════════════════════════════════════'
_txt =
'☼☾ Trade Statistics | ' + timeframe.period +
' | ' + perTxt + ' | Trade Mode : ' + tradeMode +
_sep +
'\nWin Rate : ' + str.tostring(winRate, '#.#') + '%' +
' | Trades : ' + str.tostring(totalTrades) +
'\nWin/Loss : ' + str.tostring(totalWin) + '/' + str.tostring(totalLoss) +
' | Long W/L : ' + str.tostring(bt_winL()) + '/' + str.tostring(bt_lossL()) +
' | Short W/L : ' + str.tostring(bt_winS()) + '/' + str.tostring(bt_lossS()) +
_sep +
'\nGain/Loss : ' + str.tostring(gainPct, '#.##') + '%' +
' | Initial/Final Capital : ' + str.tostring(dasCapital, '#.##') + '/' + str.tostring(estimated, '#.##') +
_sep +
'\nStatus : ' + tradeDirTxt +
(bt_dir() != 0 ?
' | Entry Price : ' + str.tostring(bt_entry()) +
' | Unrealized : ' + str.tostring((estimated / bt_cap() - 1) * 100, '#.##') + '%' +
'\nStop Loss : ' + _slTxt
: '') +
(years < lenBckTst ? '\n*** max available history for this timeframe' : '')
_statCol =
gainPct > 0 ? color.teal : gainPct < 0 ? color.red : color.gray
label.delete(statLbl)
statLbl := label.new(bar_index + 5, bt_yAnchor, _txt, color = _statCol, xloc = xloc.bar_index, style = label.style_label_left,
textcolor = color.white, textalign = text.align_left, size = size.small, force_overlay = true)
bgcolor(isBackTest and startBckTst ? startBckTst != startBckTst[1] ? color.new(color.gray, 90) :
bt_dir() == 1 ? color.new(color.teal, 92) : bt_dir() == -1 ? color.new(color.red, 92) : na : na,
title = 'Backtest Background', editable = false)
// ── Entry / exit price line ───────────────────────────────────────────────────── //
plot(bt_dir() != 0 ? bt_entry() : bt_exit() > 0 ? bt_exit() : na, 'Entry / Exit Price',
color = bt_dir() == 1 ? color.teal : bt_dir() == -1 ? color.red : color.gray,
style = plot.style_circles, display = display, editable = false, force_overlay = true)
var table logo = table.new(position.bottom_right, 1, 1)
var table logo2 = table.new(position.bottom_right, 1, 1, force_overlay = true)
if barstate.islast
table.cell(logo, 0, 0, '☼☾ ', text_size=size.normal, text_color=color.teal, tooltip = 'SoleMare Analytics')
table.cell(logo2, 0, 0, '☼☾ ', text_size=size.normal, text_color=color.teal, tooltip = 'SoleMare Analytics')