Skip to content

serceba/bjorgun

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © Bjorgum

// ________________________________________________________________ // |_______________/| // || ________________ || // || ___ __ )_____() ____ ________ ___ || // || __ __ | / __ _ / __ / / / /_ __ \ || // || _ // / / / // / / _ // // // / / / / / / || // || /__/ ___ / _/// _, / _,/ // // // || // || // // || // |||| // |/|

//@version=5

strategy( title = "Bjorgum Double Tap", shorttitle = "Bj Double Tap", overlay = true, max_lines_count = 500, max_labels_count = 500, precision = 3, default_qty_type = strategy.cash, commission_value = 0.04, commission_type = strategy.commission.percent, slippage = 1, currency = currency.USD, default_qty_value = 1000, initial_capital = 1000)

// ══════════════════════════════════ // // —————> Immutable Constants <—————— // // ══════════════════════════════════ //

string useStratTip = "Enables or disables the strategy tester allowing a change between either an indicator or a strategy." string dLongTip = "Detect long setups." string dShortTip = "Detect short setups." string FLIPTip = "Allow entry in the opposite bias while already in a position."

string startTip = "Start date & time to begin backtest period. Useful for beginning new bot. eg. Set time to now to make broker emulator in a flat position with the proper starting captial before setting alerts" string endTip = "End date & time to stop searching for setups for back testing."

string tolTip = "The difference in height allowable for the signifcant points of the pattern expressed as a percent of the pattern height. Example: The points can vary in height by 15% of the pattern height from one another." string lenTip = "The length used to calcuate significant points to form pivots for pattern detection. Example: The highest or lowest point in 50 bars." string fibTip = "The fib target extension projected from the neckline of the pattern in the direction of the pattern bias expressed as a percent. Example: 100% is a 1:1 measurment of the height from the pattern neckline." string stopPerTip = "The fib extension of the pattern height measured from the point of invalidation. Example: 0% would be the high point of a double top. 50% would be halfway between the top and the neckline." string offsetTip = "The number of bars lines are extended into the future during an ongoing pattern."

string atrStopTip = "Enables an ATR trailing stop once the target extension is breached. NOTE: This disables a take profit order in the strategy format." string atrLenTip = "The number of bars used in the ATR calculation." string atrMultTip = "The multiplier of the ATR value to subtract from the swing low or swing high point. Example: 1 is 100% of the ATR, 2 is 2x the ATR value." string lookbackTip = "The number of bars to look back to find a swing high or swing low to be used in the trailing stop calculation. Example: 1 ATR subtracted from the lowest point in 5 bars. 1 would use the lowest point within the last bar."

string tableTip = "Show the data table for trade limit levels during an active trade. (table will only show when a pattern is present on the chart, or in bar replay)." string labelTip = "Updates the double top/bottom label with 'Success' or 'Failure' and updates color based on the outcome of the pattern."

string thirdTip = "Where would you like to send your alerts?" string pPhraseTip = "A custom passphrase to authenticate your json message with a touch more security." string aTronKeyTip = "The name of your Alertatron API keys. (Add the ticker in brackets). Example: MyKeys(XBTUSD)." string tickerTip = "The ticker to be traded when using Trading Connector" string LongTip = "3Commas start long deal bot keys." string LongEndTip = "3Commas end long deal bot keys." string ShortTip = "3Commas start short deal bot keys." string ShortEndTip = "3Commas end short deal bot keys."

string dt = "Double Top"
string db = "Double Bottom" string suc = " - Success"
string fail = " - Failure" string winStr = "Target reached! 💰" string loseStr = "Stopped out... 🤷‍♂" string tabPerc = "{0, number, #.##}\n({1, number, #.##}%)"
string tcStop = "slmod slprice={0} tradeid={1}" string dExit = "'{'"content": "Bjorgum {0}\\n\\n\\t'{{ticker}}' '{{interval}}'\\n\\n\\t{1}"'}'"

string S1 = "tiny" , string P1 = "top" string S2 = "small" , string P2 = "middle" string S3 = "normal" , string P3 = "bottom" string S4 = "large" , string P4 = "left" string S5 = "huge" , string P5 = "center" string S6 = "auto" , string P6 = "right" var string tnB = "" , string A1 = "Custom Json" string altStr = "" , string A2 = "Trading Connector" string tUp = "" , string A3 = "Alertatron" string dCordWin = "" , string A4 = "3Commas" string dCordLose = "" , string A5 = "Discord"

float pos = strategy.position_size int sync = bar_index bool confirm = barstate.isconfirmed var int dir = na var float lmt = na var float stp = na string altExit = na

bool FLAT = pos == 0 bool LONG = pos > 0 bool SHORT = pos < 0 var int tradeId = 0

color col1 = color.new(#b2b5be, 15) color col2 = color.new(#b2b5be, 87) color col3 = color.new(#ffffff, 0) color col4 = color.new(#17ff00, 15) color col5 = color.new(#ff0000, 15) color col6 = color.new(#ff5252, 0)

var matrix logs = matrix.new (5, 3) var line [] zLines = array.new_line (5) var line [] tLines = array.new_line (5) var line [] bLines = array.new_line (5) var label[] bullLb = array.new_label () var label[] bearLb = array.new_label ()

int timeStart = timestamp("01 Jan 2000") int timeEnd = timestamp("01 Jan 2099")

// ══════════════════════════════════ // // —————————> User Input <——————————— // // ══════════════════════════════════ //

string GRP1 = "════  Detection and Trade Parameters  ════" bool useStrat = input.bool (true , "Use Strategy" , group= GRP1, tooltip= useStratTip) bool dLong = input.bool (true , "Detect Bottoms" , group= GRP1, tooltip= dLongTip ) bool dShort = input.bool (true , "Detect Tops" , group= GRP1, tooltip= dShortTip ) bool FLIP = input.bool (true , "Flip Trades" , group= GRP1, tooltip= FLIPTip )
float tol = input.float (15 , "Pivot Tolerance" , group= GRP1, tooltip= tolTip , minval= 1) int len = input.int (50 , "Pivot Length" , group= GRP1, tooltip= lenTip , minval= 1) float fib = input.float (100 , "Target Fib" , group= GRP1, tooltip= fibTip , minval= 0) int stopPer = input.int (0 , "Stop Loss Fib" , group= GRP1, tooltip= stopPerTip ) int offset = input.int (30 , "Line Offset" , group= GRP1, tooltip= offsetTip , minval= 0)

string GRP2 = "═══════════ Time Filter ═══════════" int startTime = input.time(timeStart , "Start Filter" , group= GRP2, tooltip= startTip)
int endTime = input.time(timeEnd , "End Filter" , group= GRP2, tooltip= endTip )

string GRP3 = "══════════ Trailing Stop ══════════" bool atrStop = input.bool (false , "Use Trail Stop" , group= GRP3, tooltip= atrStopTip ) int atrLength = input.int (14 , "ATR Length" , group= GRP3, tooltip= atrLenTip , minval= 1) float atrMult = input.float (1 , "ATR Multiplier" , group= GRP3, tooltip= atrMultTip , minval= 0) int lookback = input.int (5 , "Swing Lookback" , group= GRP3, tooltip= lookbackTip, minval= 1)

string GRP5 = "════════════ Colors ════════════" color col = input.color (col1 , "Lines        " , group= GRP5, inline= "41") color zCol = input.color (col3 , "Patterns       " , group= GRP5, inline= "42") int hWidth = input.int (1 , "" , group= GRP5, inline= "41", minval= 1) int zWidth = input.int (1 , "" , group= GRP5, inline= "42", minval= 1) color colf = input.color (col2 , "Stop Fill" , group= GRP5) color tCol = input.color (col4 , "Target Color" , group= GRP5) color sCol = input.color (col5 , "Stop Color" , group= GRP5) color trailCol = input.color (col6 , "Trail Color" , group= GRP5)

string GRP6 = "═════════  Table and Label  ═════════" bool showTable = input.bool (true , "Show Table" , group= GRP6, tooltip= tableTip) bool setLab = input.bool (true , "Update Label" , group= GRP6, tooltip= labelTip) string labSize = input.string("small" , "Label Text Size" , group= GRP6, options= [S1, S2, S3, S4, S5, S6]) string textSize = input.string("normal" , "Table Text Size" , group= GRP6, options= [S1, S2, S3, S4, S5, S6]) string tableYpos = input.string("bottom" , "Table Position" , group= GRP6, options= [P1, P2, P3]) string tableXpos = input.string("right" , "" , group= GRP6, options= [P4, P5, P6])

string GRP7 = "══════════ Alert Strings ══════════" string thirdParty = input.string(A1 , "3rd Party" , group= GRP7, tooltip= thirdTip, options= [A1, A2, A3, A4, A5]) string pPhrase = input.string("1234" , "Json Passphrase" , group= GRP7, tooltip= pPhraseTip ) string aTronKey = input.string("myKeys" , "Alertatron Key" , group= GRP7, tooltip= aTronKeyTip) string tcTicker = input.string("" , "TC Ticker" , group= GRP7, tooltip= tickerTip ) string c3Long = input.string("" , "3Comma Long" , group= GRP7, tooltip= LongTip ) string c3LongEnd = input.string("" , "3Comma Long End" , group= GRP7, tooltip= LongEndTip ) string c3Short = input.string("" , "3Comma Short" , group= GRP7, tooltip= ShortTip ) string c3ShortEnd = input.string("" , "3Comma Short End", group= GRP7, tooltip= ShortEndTip)

// ══════════════════════════════════ // // ————> Variable Calculations <————— // // ══════════════════════════════════ //

bool dif = stopPer != 0 int set = sync + offset

float atr = ta.atr (14) float sLow = ta.lowest (lookback) - (atr * atrMult) float sHigh = ta.highest (lookback) + (atr * atrMult)

float pivHigh = ta.highest (len) float pivLows = ta.lowest (len)

float hbar = ta.highestbars (len) float lbar = ta.lowestbars (len)

// ══════════════════════════════════ // // ———> Functional Declarations <———— // // ══════════════════════════════════ //

High(m) => float result = (m == 1 ? high : low)

Low(m) => float result = (m == 1 ? low : high)

perD(_p) => float result = (_p - close) / close * 100

_coords(_x, _i) => x = matrix.get (_x, _i, 0) y = matrix.get (_x, _i, 1) [int(x), y]

_arrayLoad(_x, _max, _val) =>
array.unshift (_x, _val)
if array.size (_x) > _max array.pop (_x)

_matrixPush(_mx, _max, _row) => matrix.add_row(_mx, matrix.rows (_mx), _row) if matrix.rows (_mx) > _max matrix.remove_row (_mx, 0)

_mxLog(_cond, _x, _y) => float[] _row = array.from (sync, _y, 0) if _cond _matrixPush (_x, 5, _row)

_mxUpdate(_cond, _dir, _x, y) => int m = _dir ? 1 : -1 int _end = matrix.rows (_x) -1 if _cond and y * m > matrix.get (_x, _end, 1) * m matrix.set (_x, _end, 0, sync) matrix.set (_x, _end, 1, y)

_extend(_x, _len) => for l in _x line.set_x2(l, _len)

_hLine(_l, x2, y2, y3, y4, y5, _t) => line l1 = line.new (x2 , y2, set, y2, color= col, width= hWidth) line l2 = line.new (x2 , y4, set, y4, color= col, width= hWidth) array.set (_l , 3, l1) array.set (_l , 2, l2) array.set (_l , 1, line.new (x2 , y3, set, y3, color= col, width= hWidth)) array.set (_l , 0, line.new (sync-1, _t, set, _t, color= col, width= hWidth)) linefill.new (l1 , l2, colf) if stopPer != 0 array.set (_l, 4, line.new (sync-1, y5, set, y5, color= col, width= hWidth))

_zLine(x1, y1, x2, y2, x3, y3, x4, y4) => array.set (zLines, 3, line.new (x1, y1, x2 , y2 , color= zCol, width= zWidth)) array.set (zLines, 2, line.new (x2, y2, x3 , y3 , color= zCol, width= zWidth)) array.set (zLines, 1, line.new (x3, y3, x4 , y4 , color= zCol, width= zWidth)) array.set (zLines, 0, line.new (x4, y4, sync, close, color= zCol, width= zWidth))

_label(x, y, m) => m > 0 ?
_arrayLoad (bearLb, 1, label.new (x, y, dt, color= color(na), style= label.style_label_down, textcolor= col, size= labSize)) : _arrayLoad (bullLb, 1, label.new (x, y, db, color= color(na), style= label.style_label_up, textcolor= col, size= labSize))

_labelUpdate(_x, _y, m) => if (_x or _y) and setLab label lab = array.get (m > 0 ? bearLb : bullLb, 0) string oStr = (m > 0 ? dt : db) string nStr = oStr + (_x ? suc : fail) label.set_text (lab, nStr) label.set_textcolor (lab, _x ? tCol : sCol)

_atrTrail(_cond, _lt, _s, m) => var float _stop = na var bool _flag = na var bool _trail = na _flag := _cond _stop := _s _trail := _flag ? false : _trail if atrStop and useStrat if _lt _flag := false _trail := true
_stop := m == -1 ? _lt ? sLow : math.max(_stop, sLow) : _stop _stop := m == 1 ? _lt ? sHigh : math.min(_stop, sHigh) : _stop if High(m) * m > _stop * m _flag := true _trail := false [_flag, _stop, _trail]

_inTrade(_cond, _x, _e, m) => var bool _flag = na var float _stop = na var float _limit = na line l1 = array.get (_x, 0) float lp = line.get_price(l1, sync) line l2 = array.get (_x, dif ? 4 : 2) float ls = line.get_price(l2, sync) bool win = Low (m) * m <= lp * m and not _e bool lose = High(m) * m >= ls * m and not _e _flag := _cond _stop := _e ? ls : _stop _limit := _e ? lp : _limit if win or lose
_flag := true _extend (_x , sync) _labelUpdate (win , lose, m) line.set_color (win ? l1 : l2, win ? tCol : sCol) array.fill (_x , na) array.fill (zLines, na) [_f, _s, _t] = _atrTrail (_flag , win , _stop, m) _flag := atrStop ? _f : _flag _stop := _t and _s * m < _stop * m and confirm ? _s : _stop [_flag, _stop, _t, _limit]

_double(_cond, _l, _x, m) => var bool _flag = na int _rows = matrix.rows (_x) _flag := _cond if _flag [x1, y1] = _coords (_x , _rows - 5) [x2, y2] = _coords (_x , _rows - 4) [x3, y3] = _coords (_x , _rows - 3) [x4, y4] = _coords (_x , _rows - 2) bool traded = matrix.get (_x , _rows - 2, 2) float height = math.avg (y2 , y4) - y3 float _high = y2 + height * (tol/ 100) float _low = y2 - height * (tol/ 100) float _t = y3 - height * (fib/ 100) float y5 = y2 * m < y4 * m ? y2 : y4 float y6 = y2 * m > y4 * m ? y2 : y4 float y7 = y6 - height (stopPer/100)
bool result = y1
m < y3m and y4m <= _highm and y4m >= _lowm and closem < y3*m and not (close[1]m < y3m) and not traded if result and _flag and (m > 0 ? dShort : dLong) _hLine (_l, x2, y5, y3, y6, y7, _t) _zLine (x1, y1, x2, y2, x3, y3, x4, y4) _label (x4, y6, m) matrix.set (_x, _rows - 2, 2, 1) _flag := false _flag

_scan(_l, _x, m) => var bool _cond = true _cond := _double (_cond, _l, _x, m) bool enter = _cond[1] and not _cond [f,s,t,l] = _inTrade (_cond, _l, enter, m) _cond := f _extend(_l, set) [f,s,t,l]

_populate(_n, _x, _i, _col) => for [i, _a] in _x if not na(_a) table.cell(table_id = _n, column = _i , row = i, bgcolor = na , text = _a, text_color = _col, text_size = textSize)

// ══════════════════════════════════ // // ————————> Logical Order <————————— // // ══════════════════════════════════ //

dir := not hbar ? 1 : not lbar ? 0 : dir

bool dirUp = dir != dir[1] and dir bool dirDn = dir != dir[1] and not dir

bool setUp = not hbar and dir bool setDn = not lbar and not dir

_mxLog (dirUp or dirDn, logs, dirUp ? pivHigh : pivLows) _mxUpdate (setUp or setDn, dir, logs, setUp ? pivHigh : pivLows)

[bear,ss,ts,sl] = _scan(tLines, logs, 1) [bull,ls,tl,ll] = _scan(bLines, logs, -1)

bool st = SHORT ? ts : false bool lt = LONG ? tl : false

bool sell = bear[1] and not bear bool buy = bull[1] and not bull

color ssCol = st or st[1] ? trailCol : na color lsCol = lt or lt[1] ? trailCol : na

bool longEntry = buy and (FLAT or (SHORT and FLIP)) bool shortEntry = sell and (FLAT or (LONG and FLIP))

bool dateFilter = time >= startTime and time <= endTime

tradeId += longEntry or shortEntry ? 1 : 0

lmt := atrStop ? na : shortEntry ? sl : longEntry ? ll : lmt stp := shortEntry ? ss : longEntry ? ls : stp

plot (atrStop ? ss : na, "stop", ssCol, style= plot.style_linebr) plot (atrStop ? ls : na, "limit", lsCol, style= plot.style_linebr)

bgcolor (not dateFilter ? color.new(color.red,80) : na, title= "Filter Color")

// ══════════════════════════════════ // // —————————> Data Display <————————— // // ══════════════════════════════════ //

if showTable

string   tls    = bull ? na : str.format(tabPerc, ls, perD(ls))
string   tss    = bear ? na : str.format(tabPerc, ss, perD(ss))
string   tll    = bull ? na : str.format(tabPerc, ll, perD(ll))
string   tsl    = bear ? na : str.format(tabPerc, sl, perD(sl))

string[] titles = array.from(na, bull ? na : "Bullish", bear ? na : "Bearish")

string[] stops  = array.from("Stop"  , tls, tss)
string[] limtis = array.from("Target", tll, tsl)

table    bjTab  = table.new(tableYpos + "_" + tableXpos, 3, 3, border_color= color.new(color.gray, 60), border_width= 1)

if not bear or not bull 
    _populate(bjTab, titles, 0, color.white)
    _populate(bjTab, stops,  1, color.red)
    if not (na(ll) or lt) or not (na(sl) or st)
        _populate(bjTab, limtis, 2, color.green)

// ══════════════════════════════════ // // ——————> String Variables <———————— // // ══════════════════════════════════ //

bool cSon = thirdParty == A1 bool tCon = thirdParty == A2 bool aTron = thirdParty == A3 bool c3 = thirdParty == A4 bool dCord = thirdParty == A5

if cSon and useStrat

string json = 

 "'{'
 \n    \"passphrase\": \"{0}\",
 \n    \"time\": '\"{{timenow}}\"',
 \n    \"ticker\": '\"{{ticker}}\"',
 \n    \"plot\": '{'
 \n        \"stop_price\": {1, number, #.########},
 \n        \"limit_price\": {2, number, #.########}
 \n    '}',
 \n    \"strategy\": '{'
 \n        \"position_size\": '{{strategy.position_size}}',
 \n        \"order_action\": '\"{{strategy.order.action}}\"',
 \n        \"market_position\": '\"{{strategy.market_position}}\"',
 \n        \"market_position_size\": '{{strategy.market_position_size}}',
 \n        \"prev_market_position\": '\"{{strategy.prev_market_position}}\"',
 \n        \"prev_market_position_size\": '{{strategy.prev_market_position_size}}'
 \n    '}'
 \n'}'"

altStr := str.format(json, pPhrase, stp, lmt)

if tCon and useStrat

string tcTrade = 

 "'{{strategy.order.action}}' tradesymbol={0} tradeid={1}" 
 + (atrStop ? "" : ' tpprice={2, number, #.########}') 
 + ' slprice={3, number, #.########}' 

altStr  := str.format(tcTrade, tcTicker, tradeId, lmt, stp)
tUp     := str.format(tcStop, stp, tradeId)

if aTron and useStrat

string altEnt  = aTronKey + " '{'\ncancel(which=all);\nmarket(position='{{strategy.position_size}}');\n"
string altEnd  = "'}'\n#bot"
string altBrkt = 

   (atrStop ? "stopOrder(" : "stopOrTakeProfit(")
 + (atrStop ? "" : "tp=@{0, number, #.########}, ")
 + (atrStop ? "offset=@" : "sl=@") + "{1, number, #.########}, position=0, reduceOnly=true"
 + (atrStop ? ", tag=trail" : "")
 + ");\n"

string enter = altEnt + altBrkt + altEnd 
string exit  = altEnt + altEnd

altStr  := str.format(enter, lmt, stp)
altExit := na(altExit) ? exit : altExit

string stopUpdate = aTronKey + " '{'\ncancel(which=tagged, tag=trail);\n" + altBrkt + altEnd

tUp := atrStop ? str.format(stopUpdate, lmt, stp) : tUp

if dCord and useStrat

tnB := longEntry ? db : shortEntry ? dt : tnB

string postTrade = 

 "'{'\"content\": \"```🚨 Bjorgum {0} detected 🚨\\n\\n\\t'{{ticker}}' '{{interval}}'\\n\\n\\t"
 + (atrStop ? "" : "🎯 Target: {1, number, #.########}\\n\\t") 
 + "🛑 Stop:   {2, number, #.########}```\"'}'"

altStr    := str.format(postTrade, tnB, lmt, stp)
dCordWin  := str.format(dExit, tnB, winStr)
dCordLose := str.format(dExit, tnB, loseStr)

if c3 and useStrat

c3Long  := SHORT and buy  ? str.format("[{0}, {1}]", c3ShortEnd, c3Long)  : c3Long 
c3Short := LONG  and sell ? str.format("[{0}, {1}]", c3LongEnd,  c3Short) : c3Short

// ══════════════════════════════════ // // ——————> Strategy Execution <—————— // // ══════════════════════════════════ //

strategy.entry("Long" , strategy.long , comment= "Long", when= useStrat and longEntry and dateFilter, alert_message= c3 ? c3Long : altStr) strategy.entry("Short", strategy.short, comment= "Short", when= useStrat and shortEntry and dateFilter, alert_message= c3 ? c3Short : altStr)

strategy.exit("Long Exit", "Long",
stop = stp, limit = lmt, comment = "L Exit", alert_message = c3 ? c3LongEnd : aTron ? altExit : tCon ? "closelong" : dCord ? na : altStr, alert_profit = dCord ? dCordWin : na, alert_loss = dCord ? dCordLose : na)

strategy.exit("Short Exit", "Short", stop = stp, limit = lmt, comment = "S Exit", alert_message = c3 ? c3ShortEnd : aTron ? altExit : tCon ? "closeshort" : dCord ? na : altStr, alert_profit = dCord ? dCordWin : na, alert_loss = dCord ? dCordLose : na)

// ══════════════════════════════════ // // —————> Alert Functionality <—————— // // ══════════════════════════════════ //

if (lt and ls != ls[1] or st and ss != ss[1]) and (tCon or aTron) alert(tUp, alert.freq_once_per_bar_close)

if not useStrat and (buy or sell) alert((buy ? db : dt) + ' Detected', alert.freq_once_per_bar)

// ____ __ _ ____ // ( )( ( (
// ) ) / / ) D ( // (___)_)
)(____/

About

bjorgun

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published