// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Neo
//@version=5
strategy("NEODCA 6.0",
overlay=false,
max_labels_count = 500,
pyramiding = 10,
default_qty_type = strategy.cash,
initial_capital = 100,
commission_type = strategy.commission.percent,
commission_value = 0.1,
default_qty_value = 10
)
//
// inputs
color bgray = color.rgb(128, 223, 236, 81)
color WHITE = color.rgb(210, 210, 210)
color red = color.rgb(128, 49, 49, 67)
color white = color.rgb(248, 248, 248, 14)
color olive = color.white
color blue = color.rgb(23, 43, 77)
color Yellow = color.rgb(255, 186, 75)
color BG = color.from_gradient(close,low,high ,color.rgb(16, 194, 167),color.rgb(240, 141, 71))
string s_group = "Strategy Settings"
string dca_group = "DCA Settings"
string msg_group = "massage"
string visual = "Visuals"
int offset = 15
var int glb_dealstart_bar_time = 0
int Length = 14
float ChangePercentage = input.float(title='SRP %',defval=1.4,group='SRP Settings',inline = "00",step=0.1)
float core = ta.vwma(hlc3, Length)
float below = input(55,title="⬇️",group='SRP Settings',inline = "00")
float above = input(138,title="⬆️",group='SRP Settings',inline = "00")
bool mode = input.bool(true, "long/short", tooltip = "true for long, flase for short", group = "general condation")
bool stop_loss = input.bool(true, "Stop loss", tooltip = "true for stop loss", group = "general condation")
bool big_position_protect = input.bool(false, "big position protect", group = "general condation",inline="03")
int big_position_protect_number = input.int(4, ":", group = "general condation",inline="03")
int lever = input.int(1, "lever", group = "general condation")
int Position_size = input.int(50, "Position size(%)", group = "general condation")
int initialCapital = input.int(5000, "Initial Capital", group = "general condation")
// MACD options
bool MACDType = input.string("Standard MACD", title = "MACD type", options = ["Standard MACD", "Lag MACD"], group = "MACD options") == "Standard MACD"
int fastLength = input.int(12, title="Fast MM period", minval=1, group = "MACD options")
int slowLength = input.int(26,title="Slow MM period", minval=1, group = "MACD options")
int signalLength = input.int(9,title="Signal MM period", minval=1, group = "MACD options")
int MacdEmaLength = input.int(9, title="MACD EMA period", minval=1, group = "MACD options")
bool useEma = input.string("EMA", title="Use EMA/SMA", options = ["EMA", "SMA"], group = "MACD options") == "EMA"
bool useOldAlgo = input.bool(false, title="Use Glaz algo (otherwise 'real' original zero lag)", group = "MACD options")
bool showDots = input.bool(true, title="Show symbols to indicate crossing", group = "MACD options")
float dotsDistance = input.float(1.5, title="Symbols distance factor", minval=0.1, group = "MACD options")
bool mintpbool = input.bool(true,"Minimal TP❓➔ ",group = s_group,inline="01")
float mintp = input.float(0.5,"min TP (%)",step= 0.1 , group = s_group,inline="01")/100
float maxtp = input.float(3.0,"max TP (%)",step= 0.1 , group = s_group,inline="01")/100
float minSOchange = input.float(title='Price change (%)', defval=3, step=0.1, group = dca_group,inline="02")
float minSOchange_Multi = input.float(title='Price change (%) Multi', defval=0, step=0.1, group = dca_group,inline="02")
float base = input.float(title='$ Base order', defval=710, step=1, group = dca_group)
float safety = input.float(title='DCA Multi', defval=1.5, step=1, group = dca_group,tooltip = "It Multiply the position size by this value")
int sonum = input.int(title='DCA Count', defval=8, step=1, group = dca_group,tooltip = "How Many DCA orders Do you want ?!") + 1
bool DCATYPE = input.string("Base Multiply",title ="DCA TYPE",options = ["Volume Multiply","Base Multiply"],group = dca_group) == "Volume Multiply"
bool limit_date_range = input.bool(title='Backtest Date', defval=true, group="Backtest Date")
int start_time = input.time(defval=timestamp('11 OCT 1901 00:00 +0000'), title='Start Time', group="Backtest Date")
int end_time = input.time(defval=timestamp('31 Dec 2080 00:00 +0000'), title='End Time', group="Backtest Date")
bool show_table = input(true,title= "Show Table ❓",inline = "001",group = visual)
string position = input.string("Top Right", options = ["Middle Right","Top Center","Top Right","Middle Left","Middle Center","Bottom Left","Bottom Center","Bottom Right"],title = 'Position',inline = "001",group = visual)
color textcolos = input.color(Yellow,title = "Text Color",inline = "001",group = visual)
bool showdeals = input(true,"Deal lines❓",inline = "002",group =visual )
color profitcolor = input.color(bgray,"",inline = "002",group =visual )
color socolor = input.color(red,"",inline = "002",group =visual )
color avgcolor = input.color(white,"",inline = "002",group =visual )
bool showBG = input(false,"Deal BG Color❓",inline = "003",group =visual )
color bgcolor = input.color(blue,"",inline = "003",group =visual )
bool showpnllabel = input(true,"PNL Label❓",inline = "004",group =visual )
color pnlcolor = input.color(olive,"",inline = "004",group =visual )
string msg_start = input.text_area("", "start", group = msg_group)
string msg_dca = input.text_area("", "DCA", group = msg_group)
string msg_close = input.text_area("", "close", group = msg_group)
string table_name ='NEODCA Strategy 6.0[Neo]'
var int socounter = 0
var int dealcount = 0
// Core calculation ---------{
in_date_range = true
if limit_date_range
in_date_range := time >= start_time and time <= end_time
else
in_date_range := true
vwma_above = core * (1 + (ChangePercentage / 100))
vwma_below = core * (1 - (ChangePercentage / 100))
//
up = ta.rma(math.max(ta.change(close), 0), 7)
down = ta.rma(-math.min(ta.change(close), 0), 7)
rsi = down == 0 ? 100 : up == 0 ? 0 : 100 - (100 / (1 + up / down))
mf = ta.mfi(hlc3, 7)
rsi_mfi = math.abs(rsi+mf/2)
long = low <= vwma_below and (rsi_mfi < below)
short = high >= vwma_above and (rsi_mfi > above)
// MACD part
[macdLine, signalLine, _] = ta.macd(close, fastLength, slowLength, signalLength)
hist = macdLine - signalLine
hline(MACDType ? 0 : na, "Zero Line", color = color.new(#787B86, 50))
plot(MACDType ? hist : na, title = "Histogram", style = plot.style_columns, color = (hist >= 0 ? (hist[1] < hist ? #26A69A : #B2DFDB) : (hist[1] < hist ? #FFCDD2 : #FF5252)))
plot(MACDType ? macdLine : na, title = "MACD", color = #2962FF)
plot(MACDType ? signalLine : na, title = "Signal", color = #FF6D00)
// Fast line
ma1= useEma ? ta.ema(close, fastLength) : ta.sma(close, fastLength)
ma2 = useEma ? ta.ema(ma1,fastLength) : ta.sma(ma1,fastLength)
zerolagEMA = ((2 * ma1) - ma2)
// Slow line
mas1= useEma ? ta.ema(close , slowLength) : ta.sma(close , slowLength)
mas2 = useEma ? ta.ema(mas1 , slowLength): ta.sma(mas1 , slowLength)
zerolagslowMA = ((2 * mas1) - mas2)
// MACD line
ZeroLagMACD = zerolagEMA - zerolagslowMA
// Signal line
emasig1 = ta.ema(ZeroLagMACD, signalLength)
emasig2 = ta.ema(emasig1, signalLength)
signal = useOldAlgo ? ta.sma(ZeroLagMACD, signalLength) : (2 * emasig1) - emasig2
lagHist = ZeroLagMACD - signal
plot(MACDType ? na : lagHist, title = "Histogram", style = plot.style_columns, color = (lagHist >= 0 ? (lagHist[1] < hist ? #26A69A : #B2DFDB) : (lagHist[1] < lagHist ? #FFCDD2 : #FF5252)))
zeroLine = plot(MACDType ? na : ZeroLagMACD, color=#2962FF, linewidth=2, title='MACD line')
lagSignalLine = plot(MACDType ? na : signal, color=#FF6D00, linewidth=2, title='Signal')
ribbonDiff = lagHist > 0 ? color.green : color.purple
fill(zeroLine, lagSignalLine, color=ribbonDiff)
circleYPosition = signal * dotsDistance
plot(MACDType ? na : ta.ema(ZeroLagMACD,MacdEmaLength), color=color.yellow, linewidth=2, title='EMA on MACD line')
ribbonDiff2 = lagHist > 0 ? color.green : color.purple
plotshape(MACDType == false and showDots and ta.crossover(ZeroLagMACD, signal) ? circleYPosition : na, location = location.absolute, style=shape.circle,size=size.small, color=ribbonDiff2, title='Dots')
plotshape(MACDType == false and showDots and ta.crossunder(ZeroLagMACD, signal) ? circleYPosition : na, location = location.absolute, style=shape.circle,size=size.small, color=ribbonDiff2, title='Dots')
MACDlongCondition = MACDType ? ta.crossover(macdLine, signalLine) : ta.crossover(ZeroLagMACD, signal)
MACDshortCondition = MACDType ? ta.crossunder(macdLine, signalLine) : ta.crossunder(ZeroLagMACD, signal)
table_position() =>
switch position
"Middle Right" => position.middle_right
"Top Center" => position.top_center
"Top Right" => position.top_right
"Middle Left" => position.middle_left
"Middle Center" => position.middle_center
"Bottom Left" => position.bottom_left
"Bottom Center" => position.bottom_center
"Bottom Right" => position.bottom_right
var summary_table = table.new(table_position(), 15, 33, frame_color=color.rgb(58, 58, 59, 38), frame_width=3,border_width = 2)
change_color(con)=>
con ? color.rgb(0, 149, 77) : color.rgb(152, 46, 46)
table_cell(table,_row,in1,in2)=>
table.cell(table, 0, _row,
in1,
text_color=textcolos,
bgcolor = color.rgb(58, 58, 59, 38),
text_size = size.small,
text_halign = text.align_left
)
table.cell(table, 1, _row, str.tostring(in2), text_color=WHITE,text_size = size.small,bgcolor =color.rgb(120, 123, 134, 38) )
//------------}
calcNextSOprice(pcnt) =>
if strategy.position_size > 0
strategy.position_avg_price - (math.round(pcnt / 100 * strategy.position_avg_price / syminfo.mintick)) * syminfo.mintick
else if strategy.position_size < 0
strategy.position_avg_price + (math.round(pcnt / 100 * strategy.position_avg_price / syminfo.mintick)) * syminfo.mintick
else
na
//
calcChnagefromlastdeal() =>
last_deal = strategy.opentrades.entry_price(strategy.opentrades - 1)
math.abs(((close - (last_deal) ) /close ) * 100 )
Calcprofitpercent() =>
math.abs(((close - strategy.position_avg_price ) /close ) * 100 )
// def calculate(base, SO):
// return so_size
SO = base * safety
CapitalCalculation() =>
float total = 0.0
for x= 1 to sonum - 1 by 1
so_size = SO * math.pow(safety, x-1)
total+= so_size
total + base
// plot(SO,"?111!")
// plot(CapitalCalculation(),"?!")
calculateSO(num)=>
SOv = base * math.pow(safety,num)
SOv
SOnumber()=>
(minSOchange + (socounter * minSOchange_Multi))
SOconditions(condation)=>
if condation
(calcChnagefromlastdeal() > SOnumber() ) and (close < calcNextSOprice(SOnumber()))
else
(calcChnagefromlastdeal() > SOnumber() ) and (close > calcNextSOprice(SOnumber()))
stopLoss(condation)=>
if condation
(calcChnagefromlastdeal() > SOnumber() ) and (close < calcNextSOprice(SOnumber()))
else
(calcChnagefromlastdeal() > SOnumber() ) and (close > calcNextSOprice(SOnumber()))
// -----------------------------------------------------------------------------------------------------------------------------------------------------------------
getTpCondation(so_status) =>
stepPercentage = (maxtp - mintp) / sonum
tpCondation = maxtp - stepPercentage * so_status
(tpCondation)
float Biggest_decline = 1 / (lever * Position_size / 100)
log.info(str.tostring(Biggest_decline))
log.info(str.tostring(((strategy.position_avg_price - low) / strategy.position_avg_price) > Biggest_decline))
liquidation = mode ? ((strategy.position_avg_price - low) / strategy.position_avg_price) > Biggest_decline : ((high - strategy.position_avg_price) / strategy.position_avg_price) > Biggest_decline
plotshape(liquidation and lever != 1 ? Biggest_decline : na, "liquidation", style = shape.flag,location = location.abovebar, color = color.red, text = "liquidation", force_overlay = true)
mintpclogic(so_status) =>
if mode
// (close > (strategy.position_avg_price * (1 + getTpCondation(so_status))))
(close > strategy.position_avg_price)
else
// (close < (strategy.position_avg_price * (1 - getTpCondation(so_status))))
(close < strategy.position_avg_price)
get_timestring_from_seconds(seconds) =>
if seconds >= 86400
string _string = str.tostring(math.round(seconds / 86400, 1)) + ' days'
else if seconds >= 3600
string _string = str.tostring(math.round(seconds / 3600, 1)) + ' hours'
else
string _string = str.tostring(math.round(seconds / 60, 1)) + ' mins'
get_timespan_string(start_time, end_time) =>
_seconds_diff = (end_time - start_time) / 1000
get_timestring_from_seconds(_seconds_diff)
Calcprofit()=>
(( close * strategy.position_size ) - (strategy.position_avg_price * strategy.position_size))
// var label t = na , label.delete(t) , t:= label.new(bar_index,high,str.tostring(mintpclogic()))
// plot(strategy.netprofit,"?!",display = display.data_window)
PNLlabel()=>
message = ""
if big_position_protect and socounter >= sonum - big_position_protect_number
message += "Reason: big position protect" + "\n"
else if MACDshortCondition or MACDshortCondition
message += "Reason: MACD" + "\n"
else if long or short
message += "Reason: VWMA" + "\n"
message += "PNL : " +str.tostring(math.round(Calcprofit(), 2)) + ' ' + str.tostring(syminfo.currency) + '\n'
message += "Time: " +get_timespan_string(glb_dealstart_bar_time, time)+ '\n'
message += "PNL%: " + str.tostring(math.round(Calcprofitpercent(),2))+ " %"
topy = high + (high* 0.04)
label.new(bar_index + 1,
topy,
text=message,
yloc=yloc.price,
size=size.normal,
style=label.style_label_lower_left,
textcolor=color.black,
textalign = text.align_left,
color= Calcprofit() > 0 ? pnlcolor : color.red,
force_overlay = true
)
var float removed = na
Opentrade()=>
strategy.opentrades > 0 ? 1 : 0
PNLpercentage()=> ((close - strategy.position_avg_price ) /close ) * 100
var string reason = na
tpCondition(so_status) =>
big_protect_condition = big_position_protect and so_status >= sonum - big_position_protect_number
close_tp_condition = close > (strategy.position_avg_price * (1 + getTpCondation(so_status)))
close_sl_condition = close < (strategy.position_avg_price * (1 - getTpCondation(so_status)))
if big_protect_condition
true
else
if mode
if (short or MACDshortCondition) and close_tp_condition
true
else if big_protect_condition and close_tp_condition
true
else
false
else
if (long or MACDlongCondition) and close_sl_condition
true
else if big_protect_condition and close_sl_condition
true
else
false
//--------------------------------------------------------------------------
// # Strategy Inputs # |
//--------------------------------------------------------------------------
// plot(strategy.opentrades,display = display.data_window,title = "OpenSZ")
var int dca_time = na
var float dca_price = 0
if mode
// open
if long and strategy.opentrades == 0 and in_date_range
socounter := 0
dealcount += 1
dealcount
glb_dealstart_bar_time := time
strategy.entry("LONG", strategy.long, comment="D # " + str.tostring(dealcount), qty=base / close, alert_message=msg_start)
removed := strategy.netprofit / close
// DCA
if long and SOconditions(mode) and strategy.opentrades > 0 and strategy.opentrades < sonum and (dca_price > close or dca_price == 0)
dca_price := close
socounter += 1
socounter
replaced_msg_dca = str.replace(msg_dca, "((q))", str.tostring(DCATYPE ? (strategy.position_size * safety) : calculateSO(socounter)))
strategy.entry('LONG', strategy.long, qty=DCATYPE ? (strategy.position_size * safety) : calculateSO(socounter) / close, comment="SO # " + str.tostring(socounter), alert_message=replaced_msg_dca)
// Close
if strategy.position_size > 0 and tpCondition(socounter) and close > strategy.position_avg_price and in_date_range
dca_price := 0
strategy.close("LONG", comment=" ", alert_message=msg_close)
if showpnllabel
PNLlabel()
// Stop loss
if strategy.position_size > 0 and stopLoss(mode) and stop_loss and strategy.opentrades == sonum and in_date_range
dca_price := 0
strategy.close("LONG", comment="Stop Loss", alert_message=msg_close)
if showpnllabel
PNLlabel()
else
// open
if short and strategy.opentrades == 0 and in_date_range
socounter := 0
dealcount += 1
dealcount
glb_dealstart_bar_time := time
strategy.entry("SHORT", strategy.short, comment="D # " + str.tostring(dealcount), qty=base / close, alert_message=msg_start)
removed := strategy.netprofit / close
// DCA
if short and SOconditions(mode) and not short[1] and strategy.opentrades > 0 and strategy.opentrades < sonum and dca_price < close
dca_price := close
socounter += 1
socounter
replaced_msg_dca = str.replace(msg_dca, "((q))", str.tostring(DCATYPE ? (strategy.position_size * safety) : calculateSO(socounter)))
strategy.entry('SHORT', strategy.short, qty=DCATYPE ? (strategy.position_size * safety) : calculateSO(socounter) / close, comment="SO # " + str.tostring(socounter), alert_message=replaced_msg_dca)
dca_time := time
// Close
if strategy.position_size < 0 and tpCondition(socounter) and close < strategy.position_avg_price and in_date_range
dca_price := 0
strategy.close("SHORT", comment=" ", alert_message=msg_close)
if showpnllabel
PNLlabel()
// Stop loss
if strategy.position_size < 0 and stopLoss(mode) and stop_loss and strategy.opentrades == sonum and in_date_range
dca_price := close
strategy.close("SHORT", comment="Stop Loss", alert_message=msg_close)
if showpnllabel
PNLlabel()
hp= plot(vwma_above, color=color.new(color.red, 0), force_overlay = true)
lp= plot(vwma_below, color=color.new(color.green, 0), force_overlay = true)
plotshape(long and not long[1],title="Buy",style=shape.labelup,color=color.rgb(53, 141, 56),location= location.belowbar ,size=size.tiny,text= "B",textcolor = color.white, force_overlay = true)
plotshape(short,title="Sell",style=shape.labeldown,color=color.rgb(146, 18, 13),location= location.abovebar ,size=size.tiny,text = "S",textcolor = color.white, force_overlay = true)
avg = plot(showdeals? strategy.position_avg_price : na, 'AVG Price',color= avgcolor, style=plot.style_linebr,editable = false, force_overlay = true)
sl = plot(showdeals ? calcNextSOprice(SOnumber()): na, 'SO change %', color.orange, style=plot.style_linebr,editable = false, force_overlay = true)
tp = plot(showdeals ? (mode ? strategy.position_avg_price * (1 + getTpCondation(socounter)) : strategy.position_avg_price * (1 - getTpCondation(socounter))): na, 'SO change %', color.rgb(3, 233, 245), style=plot.style_linebr,editable = false, force_overlay = true)
fill(tp, avg, color =profitcolor)
fill(avg, sl, color = socolor)
bgcolor(showBG and strategy.position_size > 0 ? color.new(bgcolor,90): na)
statusOpen()=>
Opentrade() == 0 ? str.tostring(Opentrade()) : str.tostring(Opentrade()) + "\n" + "------" + "\n" + str.tostring(syminfo.currency) + " :" + "$" + str.tostring(math.round(strategy.openprofit,2))+ "\n"
+ "------" + "\n" + "% " + " :" + str.tostring(math.round(PNLpercentage(),2))+ " %"
if barstate.isconfirmed
_row = 1
p_row = 1
if show_table
text_color = color.rgb(210, 210, 210)
bg_color = color.from_gradient(close, low, high, color.rgb(16, 194, 167), color.rgb(240, 141, 71))
// Table Title
table.cell(summary_table, 0, 0, table_name, bgcolor=bg_color, text_size=size.small, text_font_family=font.family_default)
table.cell(summary_table, 1, 0, "", bgcolor=bg_color, text_halign=text.align_left)
table.merge_cells(summary_table, 0, 0, 1, 0)
// Deal Status
table.cell(summary_table, 0, 1, 'Deal Status', bgcolor=color.rgb(58, 58, 59, 38), text_color=textcolos, text_size=size.small, text_font_family=font.family_default, text_halign=text.align_left)
table.cell(summary_table, 1, 1, statusOpen(), bgcolor=color.rgb(120, 123, 134, 38), text_color=WHITE, text_size=size.small, text_font_family=font.family_default)
_row += 1
// Required Capital
table_cell(summary_table, _row, "Required Capital", CapitalCalculation() )
_row += 1
if lever != 1
// Required Capital lever
table_cell(summary_table, _row, " Required Capital lever", initialCapital / 2 * lever)
_row += 1
// Total PNL
table_cell(summary_table, _row, "Total PNL", strategy.netprofit)
_row += 1
// Current Deep
table_cell(summary_table, _row, "current deep", strategy.opentrades)
///
//
Show all 469 lines