Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Liquidations by volume
- // Description: Shows actual liquidations on a per-candle basis, by using the difference in volume between spot and futures perpetuals markets.
- // i.e. volume on a futures market will be much higher than spot market if there are many liquidations.
- //
- // Hence, this indicator can approximate the amount of liquidations (ie, bars where there were a lot more liquidations than others) from the differenc between futures and spot volumes,
- // but it cannot distinguish the proportion of shorts versus longs liquidations, it is instead approximated with the current price bar's color,
- // which naturally suggests where the majority of liquidations happened (ie, if a price bar closes above open and hence in green, then we can suppose that
- // a majority of liquiditations were on shorts, since we know longs won). This explains why there is only one liquidation bar but colored, and not two, since we cannot separate longs or shorts liquidations.
- //
- // Long liquidation data should in theory be more accurate than short liquidation data due to the inability to short on a spot market.
- //
- // This indicator should be able to help identify trends by determining liquidation points in the chart. Focus first on the magnitude (ie, finding bars of unusually high liquidations), and only after consider the color.
- //
- // Notes:
- // - Script now removes any negative values, these values are not relevant to the indicators purpose
- // - Added an option to remove below average values to help indentify high points on the histogram
- // - Added options to plot both market volumes (spot and perpetuals) seperately
- // - Can autodetect the spot and futures markets automatically for the currently selected ticker in TradingView. It always uses the USDT spot versus USDT perpetuals for the current symbol, even if the source ticker is USD, USDC, etc. The only requirement is that USD is written in the ticker string (thanks to hamiissah for the idea to search for USD).
- // - The exchange providing the data is not specified so the script can switch to any exchange that can provide perpetuals futures data for the current pair, but in practice it is almost always Binance, and if you want, you can enable an option to ensure we always use Binance as a source, to avoid unintended data switching.
- // - Ticker autodetection also works on composite tickers (eg, BINANCE:BTCUSD+KRAKEN:BTCUSD)/2 ). The first symbol will be extracted and used, so if the composite ticker is not a simple average of the same symbol across multiple exchanges, obviously the liquidations will be wrong, but anyway there is no source of data for liquidations over composite tickers by definition.
- //
- // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
- // Original Code © Thomas_Davison
- // Modifications © NK.active
- // Extended by Tartigradia to automatically detect the symbol and add multi-timeframe support (MTF)
- //
- //@version=5
- strategy("Liquidations by volume (TG fork) Adapted Analysis", shorttitle='Liquidations by vol (TG)', format=format.volume, precision=2)
- import EliCobra/CobraMetrics/4 as cobra
- //// PLOT DATA
- disp_ind = input.string ("None" , title = "Display Curve" , tooltip = "Choose which data you would like to display", options=["Strategy", "Equity", "Open Profit", "Gross Profit", "Net Profit", "None"], group = "🐍 𝓒𝓸𝓫𝓻𝓪 𝓜𝓮𝓽𝓻𝓲𝓬𝓼 🐍")
- pos_table = input.string("Middle Left", "Table Position", options = ["Top Left", "Middle Left", "Bottom Left", "Top Right", "Middle Right", "Bottom Right", "Top Center", "Bottom Center"], group = "🐍 𝓒𝓸𝓫𝓻𝓪 𝓜𝓮𝓽𝓻𝓲𝓬𝓼 🐍")
- type_table = input.string("None", "Table Type", options = ["Full", "Simple", "None"], group = "🐍 𝓒𝓸𝓫𝓻𝓪 𝓜𝓮𝓽𝓻𝓲𝓬𝓼 🐍")
- plot(cobra.curve(disp_ind))
- cobra.cobraTable(type_table, pos_table)
- // uses the difference in volume between a spot market and a futures market to determine possible liquidations that might have taken place
- // the calculation is simple: histogram bar value = futures volume - spot volume
- // NOTES: - markets used should have the same volume equivalent i.e. volume for BTCUSDT should be measured in BTC for both spot and futures markets, some futures markets use contracts worth different amounts meaning values will differ greatly.
- // - negative values will been removed as they dont show relevant data to this indicator
- // - all values while calculated accurately, are given to interpretation, as not all of the volume difference seen on a futures market is due to liquidations. Traders making trades within a single candle time period will skew the data.
- // INPUTS
- //
- grp1 = 'Resolution'
- tf = input.timeframe('', title='Timeframe Resolution', group=grp1)
- lookBack = input.int(defval=10,title="Biggest Bar LookBack", tooltip="Select how many bars to lookback over to find the biggest bar", group=grp1)
- tf_gaps = input.bool(false, title='Timeframe gaps?', group=grp1)
- grp2 = 'Ticker autodetect'
- ticker_autodetect = input.bool(true, 'Ticker Autodetect: use current chart symbol to try to autodetect the perpetual markets?', tooltip='If enabled, will try to detect the spot and futures markets for the current symbol, by detecting where USD is written in the ticker symbol and then extract what is before as the target ticker we want, then append USDT and USDTPERP. So this only works for crypto assets listed on perpetuals markets, and it always uses USDT as the target markets, although the input ticker can be USD, USDC, etc.', group=grp2)
- ticker_autodetect_alwaysbinance = input.bool(false, 'Always use Binance?', tooltip='If false, the exchange providing the data is not specified so the script can switch to any exchange that can provide perpetuals futures data for the current pair, but in practice it is almost always Binance, and if you want, you can enable an option to ensure we always use Binance as a source, to avoid unintended data switching. This only works if Ticker Autodetect is enabled.', group=grp2)
- grp3 = 'Ticker manual selection'
- assetSpot_user = input.symbol(title="Spot symbol", defval = "binance:btcusdt", tooltip='Will be used if ticker autodetect is disabled.', group=grp3)
- assetFutures_user = input.symbol(title="Futures symbol", defval = "binance:btcusdtperp", tooltip='Will be used if ticker autodetect is disabled.', group=grp3)
- grp4 = 'Aesthetics'
- longLiqCol = input.color(title="Long liquidations color", defval = color.red, tooltip='Some people prefer to display long liquidations in red to show that bears won, others prefer to display them in green to show that longs lost. By default, they are displayed in red.', group=grp4)
- shortLiqCol = input.color(title="Short liquidations color", defval = color.green, group=grp4)
- removeBelowMean = input.bool(title="Remove below average volume differences?", defval = true, group=grp4)
- timePeriodMean = input.int(title="Lookback period to calculate mean", defval = 100, tooltip='Works only if Remove below mean volume differences is enabled.', group=grp4)
- plotSpot = input.bool(title="Plot spot market volume?", defval = false, tooltip="If disabled, spot price will still be shown in the status bar.", group=grp4)
- spotVolCol = input.color(title="Spot volume color", defval = color.yellow, group=grp4)
- plotFutures = input.bool(title="Plot futures market volume?", defval = false, group=grp4)
- futuresVolCol = input.color(title="Futures volume color", defval = color.purple, tooltip="If disabled, futures price will still be shown in the status bar.", group=grp4)
- // DATA LOADING
- //
- // Autodetect ticker
- current_ticker = ticker.standard(syminfo.tickerid) // cannot use syminfo.ticker for aggregate/composite tickers (eg, calculations to calculate the average across multiple exchanges), then we need to use other functions such as syminfo.description or ticker.standard(syminfo.tickerid) to get the full composite ticker
- usd_start_location = str.pos(current_ticker, 'USD') // autodetect where USD is located in the ticker symbol string
- ticker_target = str.substring(current_ticker, 0, usd_start_location) // extract substring before USD as the target ticker we want to find on perpetuals
- ticker_exchange = ticker_autodetect_alwaysbinance ? 'binance:' : '' // set binance as the static exchange source for the perp data if this option is enabled
- regexclean = "(?<=:)[a-zA-Z1-9]+" // clean up the extracted substring, as it can cointain other characters, such as math operators and parenthesis, we only keep letters and numbers, and only after a comma if one is specified (so we remove the exchange, because anyway we have to use Binance for perpetuals), eg, if it's an average of tickers of the same symbol at various exchanges
- ticker_target_clean = str.match(ticker_target, regexclean) // apply the cleaning regex on the ticker target (the target symbol)
- ticker_spot = ticker_exchange + ticker_target_clean + 'USDT' // concatenate previous strings and append 'USDT' for the spot market
- ticker_futures = ticker_exchange + ticker_target_clean + 'USDTPERP' // same but append 'USDTPERP' for the futures perpetuals market
- // Define tickers we fetch, either use autodetected ones or manually set ones by user
- assetSpot = ticker_autodetect ? ticker_spot : assetSpot_user
- assetFutures = ticker_autodetect ? ticker_futures : assetFutures_user
- // Fetch data
- spotVolume = request.security(assetSpot, timeframe=(tf == 'Chart' ? timeframe.period : tf), expression=volume, gaps=tf_gaps ? barmerge.gaps_on : barmerge.gaps_off)
- futuresVolume = request.security(assetFutures, timeframe=(tf == 'Chart' ? timeframe.period : tf), expression=volume, gaps=tf_gaps ? barmerge.gaps_on : barmerge.gaps_off)
- // Calculate liquidations as the difference between futures volume and spot volume shortLiqCol is green
- // NK.active => Check why colour is based on the chart close and open instead of the futuresVolume and spotVolume
- difference = futuresVolume - spotVolume
- // direction = futuresVolume > spotVolume ? shortLiqCol : longLiqCol // close > open ? shortLiqCol : longLiqCol
- direction = close > open ? shortLiqCol : longLiqCol
- // directionBool used later one to determine if its a long position (1) or short (0) => added ny NK.active
- // directionBool = close > open ? 1 : 0
- differenceSum = math.sum(difference, timePeriodMean)
- differenceMean = differenceSum / timePeriodMean
- if removeBelowMean and difference < differenceMean or difference < 0
- difference := 0
- // PLOT
- //
- plot(difference, color=direction, title='Liquidations', linewidth=2, style=plot.style_histogram)
- plot(spotVolume, color=spotVolCol, title='Spot volume', display=plotSpot ? display.all : display.status_line)
- plot(futuresVolume, color=futuresVolCol, title='Futures volume', display=plotFutures ? display.all : display.status_line)
- //
- // Show current market used as a label
- // We use `var` to only initialize the table on the first bar.
- // Also we use a table instead of a label because table do not rescale the chart, so that the chart's scale is maximized to the metrics, not the text.
- // Removed to put the cobra tate table
- // var table textDisplay = table.new(position.top_right, 1, 1, bgcolor=color.new(color.gray, 85))
- // if barstate.islast
- // table.cell(textDisplay, 0, 0, text='Spot: ' + assetSpot + '\nFutures: ' + assetFutures, text_color=color.gray, text_halign=text.align_left)
- // Code added by NK.active
- // Add code to put in buy and sell directions
- // ------------------------------------------
- // difference = futuresVolume - spotVolume // (defined above)
- // Average last 10 bars for buySignal
- // replace maxClose maxOpen with an array populated by the red and the green liquidations respectively
- //. use directionBool to see if its green or red signal
- // workout buySignal and sellSignal based on the current day being bigger than the last 10
- // From Certified_Weeb but changed to ta.highest
- highest_bar_offset = ta.highest(difference, lookBack)
- plot(highest_bar_offset, title= "Test highest_bar_offset")
- //buySignal = close > open // still to add (and) next code from loop to check last 10 bars AND THEN change close>open to futuresVolume > spotVolume
- //sellSignal = close < open // still to add (and) next code from loop to check last 10 bars AND THEN change close<open to futuresVolume < spotVolume
- buySignal = close > open and difference >= highest_bar_offset
- sellSignal = close < open and difference >= highest_bar_offset
- // plotshape(maCrossUnder, title="Lower Close", style=shape.arrowdown, color=color.yellow)
- plotshape(buySignal,style=shape.triangleup,location=location.belowbar, color=direction, title = "Buy Signal")
- if (buySignal)
- strategy.entry("My Long Entry Id", strategy.long)
- plotshape(sellSignal,style=shape.triangledown,location=location.belowbar, color=direction, title = "Sell Signal")
- if (sellSignal)
- strategy.entry("My Short Entry Id", strategy.short)
- myLabel = barstate.islast ? label.new(bar_index, high, text="Difference", tooltip = "Max10Pos" + str.tostring(highest_bar_offset)+"\n Current"+str.tostring(difference)) : na
- //plotshape(barstate.islast,style=shape.labeldown,location=location.abovebar, textcolor=color.white)
- // End of code added by NK.active
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement