// "Mystery Strategy" / "Holy Grail for ETH" // // Preconfigured for ETH 30m on Bitget // Works on: ETH since 2022-12, AVAX since 2023-3 // // (c) Stefan Reich //@version=5 strategy(shorttitle="Stefan Reich's Mystery Strategy v230", title="Stefan Reich's Mystery Strategy", overlay=true, commission_type=strategy.commission.percent, commission_value=0.07, initial_capital = 100, default_qty_type=strategy.cash, default_qty_value=1000, calc_on_every_tick = true, max_boxes_count = 500, max_lines_count = 500, max_labels_count = 500) // commission_value is an approximately correct estimate for fees+spread on ETH on typical exchanges (Bitget, Bybit) // This strategy opens few positions though, so fees+spread are not a big deal anyway. shrouded = input.bool(false) startingDate = input.time(timestamp("8 Dec 2022")) doLongs=input.bool(true, "Do longs") doShorts=input.bool(false, "Do shorts") minMoveLong = input.float(1.6, step=0.1) minMoveShort = input.float(1.6, step=0.1) arrowOffset = input.float(10) initialOffset = input.float(10) equityOffset = input.float(10) topOffset = input.float(1, step=0.25) filesSlanted = input.bool(true) ieBoxColor = input.color(color.black) ieTextColor = input.color(color.blue) positionSize = input.float(1000, "Position size in $", tooltip="After leverage") // UTILITY FUNCTIONS drift() => sumDrift = 0.0 for tradeNo = 0 to strategy.opentrades - 1 sumDrift += strategy.opentrades.size(tradeNo) result = sumDrift // macro logFloat(value, title) { plotchar(value, title, "", location.top) } // MACD inputs fast_length = input(title="Fast Length", defval=25) slow_length = input(title="Slow Length", defval=100) macd_src = input(title="Source", defval=close) signal_length = input.int(title="Signal Smoothing", minval = 1, defval = 9) sma_source = input.string(title="Oscillator MA Type", defval="EMA", options=["SMA", "EMA"]) sma_signal = input.string(title="Signal Line MA Type", defval="EMA", options=["SMA", "EMA"]) intraCandleOperation = input.bool(false, tooltip="Open or close trades within a candle") switchOnLongsAbove = input.float(-100, step=0.1, tooltip="Allow longs only if MACD is above this level") switchOnShortsBelow = input.float(100, step=0.1, tooltip="Allow shorts only if MACD is below this level") equityXOffset = input.int(10, tooltip="Move equity box to the right using this value") exitThresholdLong = input.float(999, step=0.1, tooltip="MACD histogram value to exit a long at. To use -MinMoveShort, enter 999") exitThresholdShort = input.float(999, step=0.1, tooltip="MACD histogram value to exit a short at. To use MinMoveLong, enter 999") hotSwitchOkay = input.bool(true, tooltip="Can we kill a long by opening a short and vice versa?") equityShort = input.bool(true, tooltip="Show only the new equity, no text") useEndDate = input.bool(false, tooltip="Activate the end date below") endDate = input.time(timestamp("31 Dec 2023"), tooltip="When to end the backtest or execution (if checkbox above is set)") useRelativeMACD = input.bool(false, tooltip="Use relative MACD (normalized to asset price)") // Add more inputs down here to not mess up configurations of older versions // MACD calculation fast_ma = sma_source == "SMA" ? ta.sma(macd_src, fast_length) : ta.ema(macd_src, fast_length) slow_ma = sma_source == "SMA" ? ta.sma(macd_src, slow_length) : ta.ema(macd_src, slow_length) macd = fast_ma - slow_ma signal = sma_signal == "SMA" ? ta.sma(macd, signal_length) : ta.ema(macd, signal_length) hist = macd - signal // Plot MACD plot(fast_ma, title="MACD Fast MA", color=color.yellow) plot(slow_ma, title="MACD Slow MA", color=color.blue) plotchar(macd, "MACD", "", location.top) // Relative MACD values (in preparation for Mark II strategy) factor = 1000 / slow_ma relMACD = macd * factor relSignal = signal * factor relHist = (macd - signal) * factor plotchar(relMACD, "Relative MACD", "", location.top) // logFloat plotchar(hist, "MACD Histogram", "", location.top) // logFloat plotchar(relHist, "Relative MACD Histogram", "", location.top) // logFloat actualExitLong = exitThresholdLong == 999 ? -minMoveShort : exitThresholdLong actualExitShort = exitThresholdShort == 999 ? minMoveLong : exitThresholdShort macdToUse = useRelativeMACD ? relMACD : macd histToUse = useRelativeMACD ? relHist : hist if time >= startingDate and (not useEndDate or time <= endDate) and (intraCandleOperation or barstate.isconfirmed) qty = positionSize/close if drift() < 0.0 and histToUse >= actualExitShort strategy.close_all(shrouded ? "Exit" : "MACD Green") else if drift() > 0.0 and histToUse <= actualExitLong strategy.close_all(shrouded ? "Exit" : "MACD Red") if hotSwitchOkay or drift() == 0.0 if doLongs and histToUse >= minMoveLong and macdToUse >= switchOnLongsAbove strategy.entry("Long", strategy.long, qty=qty) else if doShorts and histToUse <= -minMoveShort and macdToUse <= switchOnShortsBelow strategy.entry("Short", strategy.short, qty=qty) // PAINT TRADES & INITIAL EQUITY plusMinusFix(s) => currency = " $" str.startswith(s, "-") ? "-" + currency + str.substring(s, 1) : "+" + currency + s formatProfit(profit) => plusMinusFix(str.tostring(profit, "#,##0.00")) var int tradesPainted = 0 var label initialEquityLabel = na if na(initialEquityLabel) and time >= startingDate ieText = "⬆\nWe invest\n$" + str.tostring(strategy.initial_capital, "#,##0") + "\nand start\nthe strategy!" ieTime = startingDate-2*24*60*60*1000 // 2 days back //ieY = close*(1-arrowOffset/100) // for style_label_center //style=label.style_label_center ieY = close*(1-initialOffset/100) // for style_label_up //boxColor = color.black //textColor = color.white style = label.style_label_up //style = label.style_triangleup initialEquityLabel := label.new(ieTime, ieY, ieText, xloc=xloc.bar_time, color=ieBoxColor, textcolor=ieTextColor, tooltip="Initial equity", size=size.huge, style=style) type PaintedTrade array<line> lines array<label> labels drawTrade(bar1, bar2, price1, price2, profit, open) => t = PaintedTrade.new() t.lines := array.new<line>() t.labels := array.new<label>() totalProfit = strategy.equity // -strategy.initial_capital //line.new(bar1, price1, bar2, price2, xloc=xloc.bar_index, width = 10, color=color.black, style=line.style_arrow_right) float y1 = price1*(1-arrowOffset/100) float y2 = price2*(1-arrowOffset/100) float top1 = price1*(1-topOffset/100) float top2 = (open ? math.min(price2, low) : price2)*(1-topOffset/100) color_solid = profit > 0 ? color.lime : color.red color = color.new(color_solid, 50) if not filesSlanted y1 := math.min(y1, y2) y2 := y1 array.push(t.lines, line.new(bar1, top1, bar1, y1, color=color, width=3)) array.push(t.lines, line.new(bar2, top2, bar2, y2, color=color, width=3)) array.push(t.lines, line.new(bar1, y1, bar2, y2, xloc=xloc.bar_index, width = 10, color=color)) //, style=line.style_arrow_right) ypos = 0.6 string profitText = formatProfit(profit) yPrice = (price1+price2)/2 yBottom = (y1+y2)/2 yText = yPrice*(1-ypos)+yBottom*ypos priceTooltip = "This trade " + (str.startswith(profitText, "+") ? "made" : "lost") + " " + profitText if open profitText := "OPEN TRADE. " + str.replace(profitText, " $", "$") array.push(t.labels, label.new((bar1+bar2)/2, yText, profitText, textcolor=color.new(color_solid, 25), color=color.black, style=label.style_text_outline, size=size.huge, tooltip=priceTooltip)) // TODO: Show current equity even if there is no open trade if not na(totalProfit) //totalProfitText = "Total: " + formatProfit(totalProfit) //totalProfitText = plusMinusFix(str.tostring(math.round(totalProfit))) amount = "$" + str.tostring(totalProfit, "#,##0") //totalProfitText = "⇒ " + amount string format = na if open format := "Current\nequity:\n\n*" else if equityShort format := "*" else if profit <= 0 format := "*\nleft" else if tradesPainted > 1 format := "Now we\nhave\n*" else format := "Now we\nhave\n*." totalProfitText = str.replace(format, "*", amount) totalColor = totalProfit > 0 ? color.lime : color.orange //yTotal = yBottom+(yBottom-yText)*4 float yTotal = y2 //xTotal = (bar1+bar2)/2 int xTotal = bar2+(open ? equityXOffset : 4) days = math.round((time-startingDate)/1000.0/60/60/24+1) tooltip = "New total equity (started with $" + str.tostring(strategy.initial_capital, "#,##0") + " - " + str.tostring(days) + " " + (days == 1 ? "day" : "days") + " ago)" string style = label.style_label_left string size = size.large if open style := label.style_label_center xTotal := xTotal+15 yTotal := price2*(1-equityOffset/100) size := size.huge array.push(t.labels, label.new(xTotal, yTotal, totalProfitText, textcolor=color.new(totalColor, 25), style=style, color=color.black, size=size, tooltip=tooltip)) t method delete(PaintedTrade this) => for line in this.lines line.delete(line) for lbl in this.labels label.delete(lbl) while tradesPainted < strategy.closedtrades bar1 = strategy.closedtrades.entry_bar_index(tradesPainted) bar2 = strategy.closedtrades.exit_bar_index(tradesPainted) price1 = strategy.closedtrades.entry_price(tradesPainted) price2 = strategy.closedtrades.exit_price(tradesPainted) //direction = strategy.closedtrades.size(tradesPainted) profit = strategy.closedtrades.profit(tradesPainted) drawTrade(bar1, bar2, price1, price2, profit, false) tradesPainted := tradesPainted+1 var PaintedTrade openTrade = na var label macdLabel = na if not barstate.ishistory if not na(openTrade) openTrade.delete() if strategy.opentrades != 0 bar1 = strategy.opentrades.entry_bar_index(0) bar2 = bar_index price1 = strategy.opentrades.entry_price(0) price2 = close profit = strategy.opentrades.profit(0) openTrade := drawTrade(bar1, bar2, price1, price2, profit, true) // Show/update floating MACD value if not na(macdLabel) label.delete(macdLabel) macdValue = str.tostring(histToUse, "0.0#") lowerBound = -minMoveShort upperBound = minMoveLong macdPercent = (histToUse-lowerBound)/(upperBound-lowerBound)*100 percentText = str.tostring(macdPercent, "0") + "%" tooltip = "MACD value: " + macdValue + " (" + percentText + " between close and open)" macdColor = macdPercent >= 0 and macdPercent <= 100 ? color.blue : color.yellow macdLabel := label.new(bar_index, close, percentText, tooltip=tooltip, yloc=yloc.abovebar, textcolor=macdColor, color=color.black, style=label.style_text_outline, size=size.large) // Show unrealized P&L in data window unrealizedPnL = strategy.opentrades == 0 ? na : strategy.opentrades.profit(0) plotchar(unrealizedPnL, "Unrealized P&L", "", location.top) // logString
Travelled to 1 computer(s): mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1036597 |
Snippet name: | Mystery Strategy [Pine Script] |
Eternal ID of this version: | #1036597/2 |
Text MD5: | 987925489f1be74cd7d5a725bef3a4e5 |
Author: | stefan |
Category: | pine script |
Type: | Document |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2023-04-23 16:22:16 |
Source code size: | 11500 bytes / 262 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 191 / 46 |
Version history: | 1 change(s) |
Referenced in: | #1036598 - MACD + Levels [Pine Script] #1036603 - Mystery Strategy Mark II [Pine Script] |