QFL base scanner
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © rex_wolfe

// Quickfingers Luc (QFL) base scanner - Zaphod
// Version 1.6 (Zaphod)

//@version=5
indicator(title = "Quickfingers Luc base scanner - Zaphod", shorttitle = "QFL Zaphod", overlay = true )

// Get user input
basePeriods = input.int(title = "Base periods", tooltip = "Number of periods to look for a low that may form a new base.", defval = 36, minval = 4)
pumpPeriods = input.int(title = "Pump periods", tooltip = "Number of periods pump is above the low to confirm a new base.", defval = 8, minval = 2)
pump = input.float(title = "Pump from base (%)", tooltip = "Deal start condition.", defval = 3, step = 0.1, minval = 0) / 100
baseCrack = input.float(title = "Size of base crack (%)", tooltip = "Deal start condition.", defval = 3, step = 0.1, minval = 0.1) / 100
// Show hidden calculations
showHighest = input.bool(title = "Show highest highs", tooltip = "Shows hidden calculations that are used to find the pump from the base.", defval = false)
showLowest = input.bool(title = "Show simple lowest lows", tooltip = "Shows hidden calculations that are used to find new bases.", defval = false)

// Check pumpPeriods is not greater than basePeriods and correct if required
pumpPeriods := pumpPeriods >= basePeriods ? basePeriods - 1 : pumpPeriods

// Declare variables
var base = float(na)
var buyLimit = float(na)
var highestHigh = float(na)

// Find the lowest low
lowestLow = ta.lowest(low, basePeriods)

// Test if new base
newBase = lowestLow[pumpPeriods + 1] > lowestLow[pumpPeriods] and lowestLow[pumpPeriods] == lowestLow

// Find the highest high between the base and current
offsetHigh = ta.highest(high, pumpPeriods)
highestHigh := newBase or high > highestHigh ? offsetHigh : highestHigh[1]

// Work out current base
base := newBase ? lowestLow : base[1]

// Test if buy criteria are met and, if so, set a buy limit
buyLimit := (highestHigh - base) / base > pump and (base - low) / base > baseCrack ? base * (1 - baseCrack) : na

// Option to turn on plot of simple lows and highs
plot(showLowest ? lowestLow : na, title = "Simple lowest low", color = color.purple)
plot(showHighest ? highestHigh : na, title = "Simple highest high", color = color.purple)

// Plot base
plot(base, color = newBase ? color.new(color.white, 100) : color.new(color.blue, 0), style = plot.style_line, offset = 1 - pumpPeriods)

// Plot buy signal
plotshape(buyLimit, title="Buy flag", text="B", location=location.belowbar, style=shape.labelup, size=size.tiny, color=color.blue, textcolor=color.white)

// Send an alert
if buyLimit
    alert("QFL buy " + syminfo.tickerid + " at $" + str.tostring(buyLimit) + ".", freq = alert.freq_once_per_bar)

// Roger, Candy, Elwood, Blacky, Bill. Not yet, Captain Chaos, not yet.