Strategy · Pine Script v4 · On the chart

Hammers & Stars Strategy

by namdar-nejad

This Pine v4 strategy trades hammer and shooting star candles on the price chart.

View on GitHub

GitHub stars1on the repository
Pine versionv4older, still runs
Lines of code274
Settings25inputs
LicenceNone statedfile: MPL-2.0
Last update4 years ago28 Feb 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 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

274 lines of Pine Script v4 from exm1_complete.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

exm1_complete.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// @version=4
strategy("Hammers & Stars Strategy [v1.1]", shorttitle="HSS[v1.1]", overlay=true)

// Strategy Settings
var g_strategy      = "Strategy Settings"
atrMinFilterSize    = input(title=">= ATR Filter", type=input.float, defval=0.0, minval=0.0, group=g_strategy, tooltip="Minimum size of entry candle compared to ATR")
atrMaxFilterSize    = input(title="<= ATR Filter", type=input.float, defval=3.0, minval=0.0, group=g_strategy, tooltip="Maximum size of entry candle compared to ATR")
stopMultiplier      = input(title="Stop Loss ATR", type=input.float, defval=1.0, group=g_strategy, tooltip="Stop loss multiplier (x ATR)")
rr                  = input(title="R:R", type=input.float, defval=1.0, group=g_strategy, tooltip="Risk:Reward profile")
fibLevel            = input(title="Fib Level", type=input.float, defval=0.333, group=g_strategy, tooltip="Used to calculate upper/lower third of candle. (For example, setting it to 0.5 will mean hammers must close >= 50% mark of the total candle size)")
// Filter Settings
var g_filter        = "Filter Settings"
emaFilter           = input(title="EMA Filter", type=input.integer, defval=0, group=g_filter, tooltip="EMA length to filter trades - set to zero to disable")
i_startTime         = input(title="Start Date Filter", defval=timestamp("01 Jan 2000 13:30 +0000"), type=input.time, group=g_filter, tooltip="Date & time to begin trading from")
i_endTime           = input(title="End Date Filter", defval=timestamp("1 Jan 2099 19:30 +0000"), type=input.time, group=g_filter, tooltip="Date & time to stop trading")
// Backtester Settings
var g_tester        = "Backtester Settings"
startBalance        = input(title="Starting Balance", type=input.float, defval=10000.0, group=g_tester, tooltip="Your starting balance for the custom inbuilt tester system")
riskPerTrade        = input(title="Risk Per Trade", type=input.float, defval=1.0, group=g_tester, tooltip="Your desired % risk per trade (as a whole number)")
drawTester          = input(title="Draw Backtester", type=input.bool, defval=true, group=g_tester, tooltip="Turn on/off inbuilt backtester display")
// AutoView Settings
var g_av            = "AutoView Settings [OANDA]"
av_use              = input(title="Use AutoView?", type=input.bool, defval=false, group=g_av, tooltip="If turned on then the alerts this script generates will use AutoView syntax for auto-trading (WARNING: USE AT OWN RISK! RESEARCH THE DANGERS)")
av_oandaDemo        = input(title="Use Oanda Demo?", type=input.bool, defval=false, group=g_av, tooltip="If turned on then oandapractice broker prefix will be used for AutoView alerts (demo account). If turned off then live account will be used")
av_limitOrder       = input(title="Use Limit Order?", type=input.bool, defval=true, group=g_av, tooltip="If turned on then AutoView will use limit orders. If turned off then market orders will be used")
av_gtdOrder         = input(title="Days To Leave Limit Order", type=input.integer, minval=0, defval=2, group=g_av, tooltip="This is your GTD setting (good til day)")
av_accountBalance   = input(title="Account Balance", type=input.float, defval=1000.0, step=100, group=g_av, tooltip="Your account balance (used for calculating position size)")
av_accountCurrency  = input(title="Account Currency", type=input.string, defval="USD", options=["AUD", "CAD", "CHF", "EUR", "GBP", "JPY", "NZD", "USD"], group=g_av, tooltip="Your account balance currency (used for calculating position size)")
av_riskPerTrade     = input(title="Risk Per Trade %", type=input.float, defval=2.0, step=0.5, group=g_av, tooltip="Your risk per trade as a % of your account balance")
// PineConnector Settings
var g_pc            = "PineConnector Settings"
pc_use              = input(title="Use PineConnector?", type=input.bool, defval=false, group=g_pc, tooltip="Use PineConnector Alerts? (WARNING: USE AT OWN RISK! RESEARCH THE DANGERS)")
pc_id               = input(title="License ID", type=input.string, defval="ID", group=g_pc, tooltip="This is your PineConnector license ID")
pc_spread           = input(title="Spread", type=input.float, defval=0.5, group=g_pc, tooltip="Enter your average spread for this pair (used for offsetting entry limit order from closing price)")
pc_risk             = input(title="Risk Per Trade", type=input.float, defval=1, step=0.5, group=g_pc, tooltip="This is how much to risk per trade (% of balance or lots - based on PC settings)")
pc_prefix           = input(title="MetaTrader Prefix", type=input.string, defval="", group=g_pc, tooltip="This is your broker's MetaTrader symbol prefix (leave blank if there is none)")
pc_suffix           = input(title="MetaTrader Suffix", type=input.string, defval="", group=g_pc, tooltip="This is your broker's MetaTrader symbol suffix (leave blank if there is none)")
pc_limit            = input(title="Use Limit Order?", type=input.bool, defval=true, group=g_pc, tooltip="If true a limit order will be used, if false a market order will be used")

// Generate PineConnector alert string & prepare OANDA broker string
var broker = av_oandaDemo ? "oandapractice" : "oanda"
var symbol = pc_prefix + syminfo.ticker + pc_suffix
var limit = pc_limit ? "limit" : ""
var spread = syminfo.mintick * 10 * pc_spread
pc_entry_alert(direction, sl, tp) =>
    limit_price = direction == "buy" ? close - spread : close + spread
    price = pc_limit ? "price=" + tostring(limit_price) + "," : ""
    pc_id + "," + direction + limit + "," + symbol + "," + price + "sl=" + tostring(sl) + ",tp=" + tostring(tp) + ",risk=" + tostring(pc_risk)

// See if this bar's time happened within date filter
dateFilter = time >= i_startTime and time <= i_endTime

// Get indicator values
atr = atr(14)
ema = ema(close, emaFilter == 0 ? 1 : emaFilter)

// Custom function to convert pips into whole numbers
toWhole(number) =>
    return = atr < 1.0 ? (number / syminfo.mintick) / (10 / syminfo.pointvalue) : number
    return := atr >= 1.0 and atr < 100.0 and syminfo.currency == "JPY" ? return * 100 : return
    
// Custom function to convert whole numbers back into pips
toPips(number) =>
    return = atr >= 1.0 ? number : (number * syminfo.mintick) * (10 / syminfo.pointvalue)
    return := atr >= 1.0 and atr < 100.0 and syminfo.currency == "JPY" ? return / 100 : return
    
// Custom function to truncate (cut) excess decimal places
truncate(_number, _decimalPlaces) =>
    _factor = pow(10, _decimalPlaces)
    int(_number * _factor) / _factor
    
// Check EMA Filter
emaFilterLong = emaFilter == 0 or close > ema
emaFilterShort = emaFilter == 0 or close < ema

// Check ATR filter
atrMinFilter = abs(high - low) >= (atrMinFilterSize * atr) or atrMinFilterSize == 0.0
atrMaxFilter = abs(high - low) <= (atrMaxFilterSize * atr) or atrMaxFilterSize == 0.0
atrFilter = atrMinFilter and atrMaxFilter

// Calculate 33.3% fibonacci level for current candle
bullFib = (low - high) * fibLevel + high
bearFib = (high - low) * fibLevel + low

// Determine which price source closes or opens highest/lowest
lowestBody = close < open ? close : open
highestBody = close > open ? close : open

// Determine if we have a valid setup
validHammer = lowestBody >= bullFib and atrFilter and close != open and not na(atr) and emaFilterLong
validStar = highestBody <= bearFib and atrFilter and close != open and not na(atr) and emaFilterShort

// Check if we have confirmation for our setup
validLong = validHammer and strategy.position_size == 0 and dateFilter and barstate.isconfirmed
validShort = validStar and strategy.position_size == 0 and dateFilter and barstate.isconfirmed

//------------- DETERMINE POSITION SIZE -------------//
// Get account inputs
var tradePositionSize = 0.0
var pair = syminfo.basecurrency + "/" + syminfo.currency

// Check if our account currency is the same as the base or quote currency (for risk $ conversion purposes)
accountSameAsCounterCurrency = av_accountCurrency == syminfo.currency
accountSameAsBaseCurrency = av_accountCurrency == syminfo.basecurrency

// Check if our account currency is neither the base or quote currency (for risk $ conversion purposes)
accountNeitherCurrency = not accountSameAsCounterCurrency and not accountSameAsBaseCurrency

// Get currency conversion rates if applicable
conversionCurrencyPair = accountSameAsCounterCurrency ? syminfo.tickerid : accountNeitherCurrency ? av_accountCurrency + syminfo.currency : av_accountCurrency + syminfo.currency
conversionCurrencyRate = security(symbol=syminfo.type == "forex" ? conversionCurrencyPair : "AUDUSD", resolution="D", expression=close)

// Calculate position size
getPositionSize(stopLossSizePoints) =>
    riskAmount = (av_accountBalance * (av_riskPerTrade / 100)) * (accountSameAsBaseCurrency or accountNeitherCurrency ? conversionCurrencyRate : 1.0)
    riskPerPoint = (stopLossSizePoints * syminfo.pointvalue)
    positionSize = (riskAmount / riskPerPoint) / syminfo.mintick
    round(positionSize)
    
// Set up our GTD (good-til-day) order info
gtdTime = time + (av_gtdOrder * 1440 * 60 * 1000) // 86,400,000ms per day
gtdYear = year(gtdTime)
gtdMonth = month(gtdTime)
gtdDay = dayofmonth(gtdTime)
gtdString = " dt=" + tostring(gtdYear) + "-" + tostring(gtdMonth) + "-" + tostring(gtdDay)
//------------- END POSITION SIZE CODE -------------//

// Calculate our stop distance & size for the current bar
stopSize = atr * stopMultiplier
longStopPrice = low < low[1] ? low - stopSize : low[1] - stopSize
longStopDistance = close - longStopPrice
longTargetPrice = close + (longStopDistance * rr)
shortStopPrice = high > high[1] ? high + stopSize : high[1] + stopSize
shortStopDistance = shortStopPrice - close
shortTargetPrice = close - (shortStopDistance * rr)

// Save trade stop & target & position size if a valid setup is detected
var t_entry = 0.0
var t_stop = 0.0
var t_target = 0.0
var t_direction = 0

// Detect valid long setups & trigger alert
if validLong
    t_entry := close
    t_stop := longStopPrice
    t_target := longTargetPrice
    t_direction := 1
    tradePositionSize := getPositionSize(toWhole(longStopDistance) * 10)
    strategy.entry(id="Long", long=strategy.long, when=validLong, comment="(SL=" + tostring(truncate(toWhole(longStopDistance),2)) + " pips)")
    // Fire alerts
    if not av_use and not pc_use
        alert(message="Bullish Hammer Detected!", freq=alert.freq_once_per_bar_close)
    // Trigger PineConnector long alert
    if pc_use
        alertString = pc_entry_alert("buy", t_stop, t_target)
        alert(alertString, alert.freq_once_per_bar_close)
    // Trigger AutoView long alert
    if av_use
        alert(message="e=" + broker + " b=long q="
         + tostring(tradePositionSize) 
         + " s=" + pair
         + " t=" + (av_limitOrder ? "limit fp=" + tostring(close) : "market")
         + " fsl=" + tostring(t_stop)
         + " ftp=" + tostring(t_target)
         + (av_gtdOrder != 0 and av_limitOrder ? gtdString : ""), 
         freq=alert.freq_once_per_bar_close)
   
// Detect valid short setups & trigger alert
if validShort
    t_entry := close
    t_stop := shortStopPrice
    t_target := shortTargetPrice
    t_direction := -1
    tradePositionSize := getPositionSize(toWhole(shortStopDistance) * 10)
    strategy.entry(id="Short", long=strategy.short, when=validShort, comment="(SL=" + tostring(truncate(toWhole(shortStopDistance),2)) + " pips)")
    // Fire alerts
    if not av_use and not pc_use
        alert(message="Bearish Hammer Detected!", freq=alert.freq_once_per_bar_close)
    // Trigger PineConnector short alert
    if pc_use
        alertString = pc_entry_alert("sell", t_stop, t_target)
        alert(alertString, alert.freq_once_per_bar_close)
    // Trigger AutoView short alert
    if av_use
        alert(message="e=" + broker + " b=short q="
         + tostring(tradePositionSize)
         + " s=" + pair
         + " t=" + (av_limitOrder ? "limit fp=" + tostring(close) : "market")
         + " fsl=" + tostring(t_stop)
         + " ftp=" + tostring(t_target)
         + (av_gtdOrder != 0 and av_limitOrder ? gtdString : ""),
         freq=alert.freq_once_per_bar_close)
         
// Check if price has hit long stop loss or target
if t_direction == 1 and (low <= t_stop or high >= t_target)
    t_direction := 0
    // Cancel limit order if it hasn't been filled yet
    if pc_limit and pc_use
        alert(pc_id + ",cancellong," + symbol)
    
// Check if price has hit short stop loss or target
if t_direction == -1 and (high >= t_stop or low <= t_target)
    t_direction := 0
    // Cancel limit order if it hasn't been filled yet
    if pc_limit and pc_use
        alert(pc_id + ",cancelshort," + symbol)

// Exit trades whenever our stop or target is hit
strategy.exit(id="Long Exit", from_entry="Long", limit=t_target, stop=t_stop, when=strategy.position_size > 0)
strategy.exit(id="Short Exit", from_entry="Short", limit=t_target, stop=t_stop, when=strategy.position_size < 0)

// Draw trade data
plot(strategy.position_size != 0 or validLong or validShort ? t_stop : na, title="Trade Stop Price", color=color.red, style=plot.style_linebr)
plot(strategy.position_size != 0 or validLong or validShort ? t_target : na, title="Trade Target Price", color=color.green, style=plot.style_linebr)
plot(strategy.position_size != 0 or validLong or validShort ? tradePositionSize : na, color=color.purple, display=display.none, title="AutoView Position Size")

// Draw EMA if it's enabled
plot(emaFilter == 0 ? na : ema, color=emaFilterLong ? color.green : color.red, linewidth=2, title="EMA")

// Draw price action setup arrows
plotshape(validLong ? 1 : na, style=shape.triangleup, location=location.belowbar, color=color.green, title="Bullish Setup")
plotshape(validShort ? 1 : na, style=shape.triangledown, location=location.abovebar, color=color.red, title="Bearish Setup")

// --- BEGIN TESTER CODE --- //
// Declare performance tracking variables
var balance = startBalance
var drawdown = 0.0
var maxDrawdown = 0.0
var maxBalance = 0.0
var totalPips = 0.0
var totalWins = 0
var totalLoss = 0

// Detect winning trades
if strategy.wintrades != strategy.wintrades[1]
    balance := balance + ((riskPerTrade / 100) * balance) * rr
    totalPips := totalPips + abs(t_entry - t_target)
    totalWins := totalWins + 1
    if balance > maxBalance
        maxBalance := balance
        
// Detect losing trades
if strategy.losstrades != strategy.losstrades[1]
    balance := balance - ((riskPerTrade / 100) * balance)
    totalPips := totalPips - abs(t_entry - t_stop)
    totalLoss := totalLoss + 1
    // Update drawdown
    drawdown := (balance / maxBalance) - 1
    if drawdown < maxDrawdown
        maxDrawdown := drawdown
        
// Prepare stats table
var table testTable = table.new(position.top_right, 5, 2, border_width=1)
f_fillCell(_table, _column, _row, _title, _value, _bgcolor, _txtcolor) =>
    _cellText = _title + "\n" + _value
    table.cell(_table, _column, _row, _cellText, bgcolor=_bgcolor, text_color=_txtcolor)
    
// Draw stats table
var bgcolor = color.new(color.black,0)
if drawTester
    if barstate.islastconfirmedhistory
        // Update table
        dollarReturn = balance - startBalance
        f_fillCell(testTable, 0, 0, "Total Trades:", tostring(strategy.closedtrades), bgcolor, color.white)
        f_fillCell(testTable, 0, 1, "Win Rate:", tostring(truncate((strategy.wintrades/strategy.closedtrades)*100,2)) + "%", bgcolor, color.white)
        f_fillCell(testTable, 1, 0, "Starting:", "$" + tostring(startBalance), bgcolor, color.white)
        f_fillCell(testTable, 1, 1, "Ending:", "$" + tostring(truncate(balance,2)), bgcolor, color.white)
        f_fillCell(testTable, 2, 0, "Return:", "$" + tostring(truncate(dollarReturn,2)), dollarReturn > 0 ? color.green : color.red, color.white)
        f_fillCell(testTable, 2, 1, "Pips:", (totalPips > 0 ? "+" : "") + tostring(truncate(toWhole(totalPips),2)), bgcolor, color.white)
        f_fillCell(testTable, 3, 0, "Return:", (dollarReturn > 0 ? "+" : "") + tostring(truncate((dollarReturn / startBalance)*100,2)) + "%", dollarReturn > 0 ? color.green : color.red, color.white)
        f_fillCell(testTable, 3, 1, "Max DD:", tostring(truncate(maxDrawdown*100,2)) + "%", color.red, color.white)
// --- END TESTER CODE --- //

Overview

Entry candles can be filtered by size relative to ATR and by an optional EMA, and a Fibonacci level defines how far into the candle the close must be. Stop loss is an ATR multiple and take profit follows a risk to reward ratio. It adds a date filter, a built-in backtest display, and alert formatting for the AutoView and PineConnector order services.

Details

Published by

namdar-nejad on GitHub

Type

Strategy, Pine Script v4

Draws

On the price chart

Category

Candlestick patterns

Markets

Gold

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
>= ATR Filterfloat0.0atrMinFilterSize
<= ATR Filterfloat3.0atrMaxFilterSize
Stop Loss ATRfloat1.0stopMultiplier
R:Rfloat1.0rr
Fib Levelfloat0.333fibLevel
EMA Filterint0emaFilter
Start Date Filtertimetimestamp("01 Jan 2000 13:30 +0000")i_startTime
End Date Filtertimetimestamp("1 Jan 2099 19:30 +0000")i_endTime
Starting Balancefloat10000.0startBalance
Risk Per Tradefloat1.0riskPerTrade
Draw BacktesterbooltruedrawTester
Use AutoView?boolfalseav_use
Show all 25 settings
SettingTypeDefaultVariable
Use Oanda Demo?boolfalseav_oandaDemo
Use Limit Order?booltrueav_limitOrder
Days To Leave Limit Orderint2av_gtdOrder
Account Balancefloat1000.0av_accountBalance
Account CurrencystringUSDav_accountCurrency
Risk Per Trade %float2.0av_riskPerTrade
Use PineConnector?boolfalsepc_use
License IDstringIDpc_id
Spreadfloat0.5pc_spread
Risk Per Tradefloat1pc_risk
MetaTrader Prefixstringpc_prefix
MetaTrader Suffixstringpc_suffix
Use Limit Order?booltruepc_limit
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

330 stars

Exceeded Candle [Alorse] is a mean-reversion strategy that identifies candlestick engulfing patterns combined with Bollinger Bands filters. It enters a long position when a green candle surpasses the body of the previous red candle while price is below the mid

Strategy v4 Mean reversionCandlestick patterns
Updated 2 months ago · None stated GitHub repository of Exceeded candle [Alorse]
285 stars

Mean Reversion Strategy is an overlay strategy that identifies pullbacks using a long-term EMA, RSI, and candlestick patterns. It generates long signals when a bullish engulfing candle forms below the EMA while RSI is oversold, and short signals when a bearish

Strategy v4 Mean reversionCandlestick patterns
Updated 3 years ago · None stated GitHub repository of Mean Reversion Strategy

ESU2023-10M - V1

by dearvn
257 stars

ESU2023-10M - V1 is an intraday trend-reversal strategy designed for index futures contracts on the price chart. It calculates a 3-period moving average of candle highs and lows alongside specific three-bar price action patterns to detect short-term swing high

Strategy v5 TrendCandlestick patterns
Updated 6 weeks ago · None stated GitHub repository of ESU2023-10M - V1

STRG One Bar Pursuit

by harryguiacorn
219 stars

The STRG One Bar Pursuit strategy identifies single-bar momentum reversals by monitoring shifts between bullish and bearish candlesticks starting from the year 2024. It enters a long position when a bullish candle follows a bearish candle and enters a short po

Strategy v5 Candlestick patternsMean reversion
Updated 1 year ago · None stated GitHub repository of STRG One Bar Pursuit
218 stars

This strategy identifies trade opportunities based on candlestick wick imbalances relative to the Average True Range. It enters positions when candle wicks exceed defined thresholds and filters out doji candles using a minimum body ATR requirement. Exits are h

Strategy v6 Candlestick patternsVolatility & bands Repaints
Updated 3 months ago · None stated GitHub repository of Super Negative R:R Wick Strategy

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