Strategy · Pine Script v4 · On the chart

(IK) Base Break Buy

by hasnocool· code credited to userIan

This price-chart strategy marks a base when enough recent bar bottoms cluster within a set deviation of the current bottom, then ignores new bases that sit too close to existing ones.

View on GitHub

GitHub stars106on the repository
Pine versionv4older, still runs
Lines of code102
Settings13inputs
LicenceGPL-3.0
Last update2 years ago18 Sep 2024

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 strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

102 lines of Pine Script v4 from (IK) Base Break Buy.pine, published under GPL-3.0. Keep the author's credit and licence lines when you reuse it.

(IK) Base Break Buy.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © userIan
//@version=4
strategy("(IK) Base Break Buy", overlay=true, pyramiding=6, precision=2, default_qty_type=strategy.cash, initial_capital=100.0, currency="USD", commission_type=strategy.commission.percent, commission_value=0.1)
// == INPUT ==
i_baseMax      = input(group="Base Calculations", title="Max Bases", type=input.integer, defval=3, minval=1, maxval=10)                                   // max amount of bases on the chart at any specific time
i_dev          = input(group="Base Calculations", title="Base Area Deviation", type=input.float, defval=0.005, minval=0.0, maxval=1.0)                    // if enough recent bars had bottoms within this deviation of the current bar's bottom, a base is created 
i_baseDev      = input(group="Base Calculations", title="Unique Base Deviation", type=input.float, defval=0.05, minval=0.0, maxval=1.0)                   // bases cannot be created if they fall within this deviation of an extant base
i_baseSource   = input(group="Base Calculations", title="Base Source", options=["Close or Open", "Low"], defval="Close or Open")                          // should base calcuations be based off of candlestick closes and opens (whichever is lower), or candlestick lows
i_lookback     = input(group="Base Calculations", title="Lookback", type=input.integer, defval=100)                                                       // how many bars back do we check to confirm current bases
i_confLevel    = input(group="Base Calculations", title="Confidence Level", type=input.float, defval=0.01, minval=0.0, maxval=1.0)                        // what percentage of historical bars bottoming within deviation are needed to confirm a base
i_breakThresh  = input(group="Base Break Detection", title="Break Threshold", type=input.float, defval=0.02, minval=0.0, maxval=1.0)                      // how far (by percentage) does price have to fall below a base to constitute a 'break'
i_breakWindow  = input(group="Base Break Detection", title="Break Window", type=input.integer, defval=5)                                                  // how many bars should we allow for price to fall below the break threshold before it's no longer a tradable break
i_initialOrder = input(group="Order Settings", title="Initial Order Capital", type=input.float, defval=0.2, minval=0.0, maxval=1.0)                       // what percentage of capital to use in initial trade entry
i_safetyCount  = input(group="Order Settings", title="Safety Order Max Count", type=input.integer, defval=3, minval=0, maxval=5)                          // maximum amount of safety orders per trade. remaining capital after initial entry will be divided evenly among these 
i_safetyThresh = input(group="Order Settings", title="Safter Order Threshold", type=input.float, defval=0.03, minval=0.0, maxval=1.0)                     // what percentage does price need to fall to activate a safety order
i_stopLoss     = input(group="Order Settings", title="Stop Loss", type=input.float, defval=0.2, minval=0.0, maxval=1.0)                                   // what percentage does price need to fall to activate a stop loss
i_stopLossType = input(group="Order Settings", title="Stop Loss Type", options=['From Initial Entry', 'From Price Average'], defval='From Price Average') // calculate static stop loss based on price at first entry, or dynamic stop loass based on position average price
// == FUNCTIONS ==
// is _val1 within the deviation (_dev) of _val2?
f_isCloseTo(_val1, _val2, _dev) => (_val1 <= _val2*(1+_dev)) and (_val1 >= _val2*(1-_dev)) 
// is this confirmed base (_val) distant enough (outside of deviation _dev) from another confirmed base (in _arr)?
f_newBase(_val, _arr, _dev) =>  
    result = true
    if array.size(_arr) > 0
        for i = 0 to array.size(_arr)-1
            if (_val <= array.get(_arr, i)*(1+_dev)) and (_val >= array.get(_arr, i)*(1-_dev))
                result := false
    result
    
// == VARIABLES ==
var bases          = array.new_float()                                                  // reference to every current base
var closestBase    = float(na)                                                          // the closest base to currenct price (only below price)
var brokenBase     = float(na)                                                          // the base that has been recently broken
var baseBreakIndex = int(na)                                                            // when the most recent base was broken
var takeProfit     = float(na)                                                          // dynamic take profit percentage base on severity of base break
var safetyOrderQty = ((strategy.initial_capital*(1-i_initialOrder))/i_safetyCount)/100  // percentage of capital to use for each safety order
var safetyCount    = 0                                                                  // keep track of how many safety orders we've made
// == LOGIC ==
// detect bases and add unique bases to base array
currentBot = i_baseSource == "Low" ? low : min(close,open)
count = 0
for i = 1 to i_lookback
    bot = i_baseSource == "Low" ? low[i] : min(close[i],open[i])
    if f_isCloseTo(currentBot, bot, i_dev)
        count := count +1   
if count >= (i_lookback * i_confLevel) and f_newBase(currentBot, bases, i_baseDev)
    array.unshift(bases, currentBot) 
// prune base array 
if array.size(bases) > i_baseMax
    array.pop(bases)
    
// detect base break
if crossunder(close, closestBase) and strategy.position_size == 0
    baseBreakIndex := bar_index
    brokenBase     := closestBase 
    
// reset baseBreak if window has expired; this is no longer a tradable break
if (bar_index - baseBreakIndex > i_breakWindow) and strategy.position_size == 0
    brokenBase := na
// update closest base
if array.size(bases) > 0
    array.sort(bases, order.descending)
    for i = 0 to array.size(bases)-1
        if array.get(bases, i) < close 
            closestBase := array.get(bases,i)
            break
// reset safety count if a trade has just been exited
if strategy.position_size == 0 
    safetyCount := 0
// == ENTRY AND EXIT ==
// enter trade if break is confirmed and set the takeProfit percentage
if close < (brokenBase * (1-i_breakThresh)) and strategy.position_size == 0 and barstate.isconfirmed
    strategy.entry(id="Long", long=strategy.long, qty=(strategy.initial_capital * i_initialOrder)/close, comment='buy')
    takeProfit := 1-(close/brokenBase) 
    
// safety order
if close < (strategy.position_avg_price * (1-i_safetyThresh)) and safetyCount < i_safetyCount
    safetyCount := safetyCount + 1
    strategy.entry(id="Long", long=strategy.long, qty=(strategy.initial_capital * safetyOrderQty)/close, comment='safety')
// exit trade
strategy.exit(id="Long", stop=i_stopLossType == "From Price Average" ? strategy.position_avg_price * (1-i_stopLoss) : brokenBase * (1-i_stopLoss), comment='sell-stop')
if (close > strategy.position_avg_price * (1+takeProfit)) and barstate.isconfirmed  
    strategy.close("Long", comment='sell-profit')
    brokenBase := na
// == PLOT ==   
plotTimer = bar_index % 2 == 0  // this creates a dashed line   
plot(array.size(bases) > 0 and plotTimer ? array.get(bases,0)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 1 and plotTimer ? array.get(bases,1)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 2 and plotTimer ? array.get(bases,2)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 3 and plotTimer ? array.get(bases,3)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 4 and plotTimer ? array.get(bases,4)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 5 and plotTimer ? array.get(bases,5)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 6 and plotTimer ? array.get(bases,6)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 7 and plotTimer ? array.get(bases,7)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 8 and plotTimer ? array.get(bases,8)  : na, color=color.white, style=plot.style_linebr)
plot(array.size(bases) > 9 and plotTimer ? array.get(bases,9)  : na, color=color.white, style=plot.style_linebr)
plot(closestBase == closestBase[1] and strategy.position_size == 0 ? closestBase : na, color=color.yellow, style=plot.style_linebr)                                 // yellow line for closest base (if not in trade)
plot(brokenBase, color=color.purple, style=plot.style_linebr)                                                                                                       // purple line for the broken base that triggered the trade
plot(strategy.position_avg_price * (1+takeProfit), color=color.silver, style=plot.style_linebr)                                                                     // silver line for target profit
plot(i_stopLossType == "From Price Average" ? strategy.position_avg_price * (1-i_stopLoss) : brokenBase * (1-i_stopLoss), color=color.red, style=plot.style_linebr) // red line for stop loss
Expand (112 lines)

Overview

A buy is considered when price falls a chosen percentage below a base inside a limited bar window. It spends a share of capital on the first entry and can add safety orders as price falls further, up to a maximum count. A percentage stop loss is measured from the first entry or the position average.

Details

Published by

hasnocool on GitHub

Code credit

userIan, as written in the script's header

Type

Strategy, Pine Script v4

Draws

On the price chart

Category

Support & resistance, Breakout, Mean reversion

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

  • The strategy can add several entries in the same direction

Topics

analysisbtcusdtcryptocurrencydatapandaspythonsimulationtradingtradingview

Settings

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

SettingTypeDefaultVariable
Max Basesint3i_baseMax
Base Area Deviationfloat0.005i_dev
Unique Base Deviationfloat0.05i_baseDev
Base SourcestringClose or Openi_baseSource
Lookbackint100i_lookback
Confidence Levelfloat0.01i_confLevel
Break Thresholdfloat0.02i_breakThresh
Break Windowint5i_breakWindow
Initial Order Capitalfloat0.2i_initialOrder
Safety Order Max Countint3i_safetyCount
Safter Order Thresholdfloat0.03i_safetyThresh
Stop Lossfloat0.2i_stopLoss
Show all 13 settings
SettingTypeDefaultVariable
Stop Loss TypestringFrom Price Averagei_stopLossType
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

1 stars

The strategy detects range expansion by comparing the previous bar's range to its ATR multiple. It places pending stop entries above highs of up bars or below lows of down bars. On trigger it enters positions with take profit and stop loss in ticks using OCA g

Strategy v6 Volatility & bandsSupport & resistance
Updated 5 days ago · Apache-2.0 GitHub repository of PF probe 97 - tp/sl gap reversal oca

Pivot Points - S/R Trading

by Basant1Saini
1 stars

Calculates classic support and resistance pivot levels using Traditional, Fibonacci, or Camarilla formulas from a higher timeframe. The strategy offers two execution modes: Bounce mode trades reversals within a customizable percentage buffer of support and res

Strategy v5 Support & resistanceBreakout
Updated 7 months ago · None stated GitHub repository of Pivot Points - S/R Trading
1 stars

This strategy identifies pivot-based Darvas Box levels on the price chart and trades re-entries following box sweeps. A long position arms when the price dips below the lower boundary and triggers when it closes back inside, provided the price is above a highe

Strategy v6 Support & resistanceBreakout
Updated 2 months ago · None stated GitHub repository of TN Sovereign Darvas Box v6

This trend-following strategy executes a classic Donchian channel breakout system designed to cross-validate backtest results against external framework benchmarks. It triggers a long entry when the closing price breaks above the highest high of the prior entr

Strategy v6 BreakoutTrend
Updated today · AGPL-3.0 GitHub repository of Forven S01509 - Simple Donchian 20/10 Breakout

More strategys

Trade Your Charts With a Regulated Broker

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

Compare brokers