Ultimate Strategy Template (Advanced Edition)
Ultimate Strategy Template (Advanced Edition)
// This source code is subject to the terms of the Mozilla Public License 2.0 at
https://mozilla.org/MPL/2.0/
// © Daveatt
// # ========================================================================= #
// # | SAMPLE INDICATOR |
// # ========================================================================= #
// //@version=5
//indicator(title='Moving Average Cross', shorttitle='Moving Average Cross',
overlay=true, precision=6, max_labels_count=500, max_lines_count=500)
// // MA
// f_ma(smoothing, src, length) =>
// rma_1 = ta.rma(src, length)
// sma_1 = ta.sma(src, length)
// ema_1 = ta.]ema(src, length)
// iff_1 = smoothing == 'EMA' ? ema_1 : src
// iff_2 = smoothing == 'SMA' ? sma_1 : iff_1
// smoothing == 'RMA' ? rma_1 : iff_2
// # ========================================================================= #
// # | SAMPLE INDICATOR |
// # ========================================================================= #
VERSION = "V7"
SCRIPT_NAME = "BEST Strategy Template " + VERSION
// # ========================================================================= #
// # | STRATEGY |
// # ========================================================================= #
// These values are used both in the strategy() header and in the script's relevant
inputs as default values so they match.
// Unless these values match in the script's Inputs and the TV backtesting
Properties, results between them cannot be compared.
InitCapital = 10000000
InitPosition = 2.0
InitCommission = 0.075
InitPyramidMax = 1
CalcOnorderFills = false
ProcessOrdersOnClose = true
CalcOnEveryTick = false
CloseEntriesRule = "FIFO"
strategy(title=SCRIPT_NAME, shorttitle=SCRIPT_NAME,
overlay=true, pyramiding=InitPyramidMax, initial_capital=InitCapital,
default_qty_type=strategy.percent_of_equity,
process_orders_on_close=ProcessOrdersOnClose,
default_qty_value=InitPosition, commission_type=strategy.commission.percent,
commission_value=InitCommission, calc_on_order_fills=CalcOnorderFills,
calc_on_every_tick=CalcOnEveryTick,
precision=9, max_lines_count=500, max_labels_count=500)
// # ========================================================================= #
// # ========================================================================= #
// # || Alerts ||
// # ========================================================================= #
// # ========================================================================= #
TradeDateIsAllowed() =>
DateFilter ? time >= i_startTime and time <= i_endTime : true
// Hard Exit
// # ========================================================================= #
// # | Stop Loss |
// # ========================================================================= #
// # ========================================================================= #
// # | Take Profit |
// # ========================================================================= #
// # ========================================================================= #
// # | Stop Loss to Breakeven |
// # ========================================================================= #
// # ========================================================================= #
// # | Custom Exit |
// # ========================================================================= #
BIG_NUMBER_COUNT = 1000
// variables initialisation
ext_source = nz(ext_source_)
// 1 is bull signal
bull = ext_source == 1
// -1 is bear signal
bear = ext_source == -1
plotshape(
series = bull and not bull[1],
title = "Buy",
style = shape.triangleup,
location = location.bottom,
color = color.new(color = color.green, transp = 0),
size = size.normal
)
plotshape(
series = bear and not bear[1],
title = "Sell",
style = shape.triangledown,
location = location.top,
color = color.new(color = color.red, transp = 0),
size = size.normal
)
// Entry Price
entry_price = ta.valuewhen(condition=(bear[1] and strategy.position_size[1] >= 0)
or (bull[1] and strategy.position_size[1] <= 0), source=close, occurrence=0)
entry_price_long = ta.valuewhen(condition=(bull and strategy.position_size <= 0),
source=close, occurrence=0)
entry_price_short = ta.valuewhen(condition=(bear and strategy.position_size >= 0),
source=close, occurrence=0)
oktoTradeDaily = true
streakLossLen := if newLoss
nz(streakLossLen[1]) + 1
else
if strategy.wintrades > strategy.wintrades[1] or strategy.eventrades >
strategy.eventrades[1]
0
else
nz(streakLossLen[1])
streakWinLen := if newWin
nz(streakWinLen[1]) + 1
else
if strategy.losstrades > strategy.losstrades[1] or strategy.eventrades >
strategy.eventrades[1]
0
else
nz(streakWinLen[1])
// trailing
// Determine trail stop loss prices
var float longTrailStopPrice = 0.0
var float shortTrailStopPrice = 0.0
var float final_SL_Long = 0.0
var float final_SL_Short = 0.0
if signal_candle[1]
MaxReached := strategy.position_size > 0 ? high : low
// Update Max point reached during trade (used both for trailing stop reference
point and in-trade max drawdown calcs).
// start trailing only when beyong the breakeven point
if strategy.position_size > 0
longTrailStopPrice := MaxReached * (1 - TrailPerc)
else if strategy.position_size < 0
shortTrailStopPrice := MaxReached * (1 + TrailPerc)
// Use this function to return the correct pip value for pips on Forex symbols
pip() => syminfo.mintick
// ATR
// Function atr (average true range) returns the RMA of true range.
// True range is max(high - low, abs(high - close[1]), abs(low - close[1]))
atr_stop = ta.atr(atrStopLength)
atr_tp1 = ta.atr(atrTakeProfitLength1)
// ATR used for Risk:Reward
var float RR_STOP_ATR = 0.0
//RR_STOP_ATR := nz(RR_STOP_ATR[1])
var float RR_TP1_ATR = 0.0
//RR_TP1_ATR := nz(RR_TP1_ATR[1])
if use_SL_Percent
final_SL_Long := longPercStopPrice
else if use_SL_ATR
final_SL_Long := entry_price_long - RR_STOP_ATR * riskRatioATR
else if (strategy.position_size >= 0 and bear)
if use_SL_Percent
final_SL_Short := shortPercStopPrice
else if use_SL_ATR
final_SL_Short := entry_price_short + RR_STOP_ATR * riskRatioATR
if use_SL_Trail
if strategy.position_size > 0
final_SL_Long := longTrailStopPrice
else if strategy.position_size < 0
final_SL_Short := shortTrailStopPrice
// # ========================================================================= #
// # | Stop Loss To Breakeven |
// # ========================================================================= #
var bool SL_BE_REACHED = false
var bool is_SL_REACHED = false
current_profit = strategy.opentrades.profit(strategy.opentrades - 1)
if strategy.position_size[1] > 0
if not SL_BE_REACHED
if not SL_BE_REACHED
// Session calculations
// The BarInSession function returns true when
// the current bar is inside the session parameter
BarInSession(sess) =>
time(timeframe.period, sess) != 0
in_session = BarInSession(Session)
okToTradeInSession = CloseSession ? in_session : true
new_session = in_session and not in_session[1]
// Orders part
longs_opened = strategy.position_size > 0
shorts_opened = strategy.position_size < 0
trades_opened = strategy.position_size != 0
longs_opened_in_session = CloseSession and longs_opened
shorts_opened_in_session = CloseSession and shorts_opened
// trades_opened_in_session = CloseSession and trades_opened
// Go long
longCondition = bull
if longCondition and okToTrade and okToTradeInSession and open_all_longs
alert_message_long_txt = "entry: " + str.tostring(close) + " sl: " +
str.tostring(final_SL_Long) + " tp: " + str.tostring(TP1longPrice)
strategy.entry('Long', strategy.long, alert_message=alert_message_long_txt,
comment = alert_message_long_txt)
// Go Short
shortCondition = bear
if shortCondition and okToTrade and okToTradeInSession and open_all_shorts
alert_message_short_txt = "entry: " + str.tostring(close) + " sl: " +
str.tostring(final_SL_Short) + " tp: " + str.tostring(TP1shortPrice)
strategy.entry('Short', strategy.short, alert_message=alert_message_short_txt,
comment = alert_message_short_txt)
// Execute Exits
if closeOnOpposite and strategy.position_size > 0 and shortCondition // and
open_all_shorts
strategy.close(id='Long', comment='Short Signal\nClose Long')
// # ========================================================================= #
// # | Custom User-Defined close |
// # ========================================================================= #
// # ========================================================================= #
// # | Custom template close |
// # ========================================================================= #
// # ========================================================================= #
// # | SL/TP1/TP2 exits |
// # ========================================================================= #
// Close all positions at the end of each session regardeless of their profit/loss
if not okToTradeInSession and close_all and trades_opened
strategy.close_all()
if close_strat
// close all existing orders
strategy.close_all()
// # ========================================================================= #
// # | Entry Price |
// # ========================================================================= #
// # ========================================================================= #
// # | Table |
// # ========================================================================= #
f_location() =>
_loc = ""
_loc
tradeDirection(_size) =>
_size < 0 ? "Short" : "Long"
// Get the biggest max trade run up value from all of the open trades.
maxOpenTradeRunUp() =>
maxRunup = 0.0
for tradeNo = 0 to strategy.opentrades - 1
maxRunup := math.max(maxRunup, strategy.opentrades.max_runup(tradeNo))
result = maxRunup
// Get the biggest max trade drawdown value from all of the open trades.
maxTradeDrawDown() =>
maxDrawdown = 0.0
for tradeNo = 0 to strategy.opentrades - 1
maxDrawdown := math.max(maxDrawdown,
strategy.opentrades.max_drawdown(tradeNo))
result = maxDrawdown
avgProfit = 0.0
for tradeNo = 0 to strategy.opentrades - 1
avgProfit += strategy.opentrades.entry_price(tradeNo)
tradeOpenNbLongsShorts() =>
nbLongs = 0
nbShorts = 0
size = strategy.opentrades.size(tradeNo)
if size > 0
nbLongs += 1
else
nbShorts += 1
[nbLongs, nbShorts]
nb_row := tradeNo + 1
str_tradeNo = str.tostring(nb_row)
str_direction = tradeDirection(strategy.opentrades.size(tradeNo))
str_entry_Price = str.tostring(strategy.opentrades.entry_price(tradeNo),
format.mintick)
str_entry_Time = str.format_time(strategy.opentrades.entry_time(tradeNo),
"yyyy-MM-dd HH:mm", syminfo.timezone)
str_profit_loss = str.tostring(strategy.opentrades.profit(tradeNo), "#.##")
str_max_DD = str.tostring(strategy.opentrades.max_drawdown(tradeNo),
"#.##")
str_max_runUP = str.tostring(strategy.opentrades.max_runup(tradeNo),
"#.##")
str_equity = str.tostring(strategy.equity, "#.##") + " " +
strategy.account_currency
LastRow = strategy.opentrades + 2
if nbLongs > 0
str_nbLongsShorts := "Opened Longs: " + str.tostring(nbLongs)
if nbShorts > 0
str_nbLongsShorts := str_nbLongsShorts + "\n"
if nbShorts > 0
str_nbLongsShorts := str_nbLongsShorts + "Opened Shorts: " +
str.tostring(nbShorts)
// // # ========================================================================= #
// // # | PIE CHART |
// // # ========================================================================= #
// color CLR = na
// for i = 0 to 360 by 1
// x0 = int(r*math.sin(math.toradians(i)))
// y0 = int(r*math.cos(math.toradians(i)))
// x = int(R*math.sin(math.toradians(i)))
// y = int(R*math.cos(math.toradians(i)))
// L3=label.new(bar_index+p_x+R+ int(
(r+R)/2*math.sin(math.toradians((C1+C2)/2))),close+ int(
(r+R)/2*math.cos(math.toradians((C1+C2)/2))) ,"ETH.D = "+ str.tostring(loss_rate)
+ " %" ,style=
label.style_none,textcolor=color.white ,textalign=text.align_center
,size=size.normal,tooltip="Loss Rate")
// label.delete(L3[1])
if strategy.position_size == 0
or (strategy.position_size > 0 and strategy.position_size[1] < 0)
or (strategy.position_size < 0 and strategy.position_size[1] > 0)
is_TP1_REACHED := false
SL_BE_REACHED := false