Custom Studies Examples
Requesting Data for Another Ticker
- Come up with a new ticker name to display your data and set up your server to return valid SymbolInfo for this new ticker.
- Also, set up the server to return valid historical data for this ticker.
- Add custom_indicators_getter key to the widget constructor. Its value is a function that returns a Promise object with a list of custom indicators.
- (Optional) Update your widget's initialization code to create this indicator when the chart is ready.
- JavaScript
- TypeScript
custom_indicators_getter: function(PineJS) {
return Promise.resolve([
{
name: 'Equity',
metainfo: {
_metainfoVersion: 51,
id: 'Equity@tv-basicstudies-1',
description: 'Equity',
shortDescription: 'Equity',
is_price_study: true,
isCustomIndicator: true,
format: {
type: 'price',
// Precision is set to one digit, e.g. 777.7
precision: 1,
},
plots: [{id: 'plot_0', type: 'line'}],
defaults: {
styles: {
plot_0: {
linestyle: 0,
visible: true,
// Make the line thinner
linewidth: 1,
// Plot type is Line
plottype: 2,
// Show price line
trackPrice: true,
// Set the plotted line color to dark red
color: '#880000'
}
},
inputs: {}
},
styles: {
plot_0: {
// Output name will be displayed in the Style window
title: 'Equity value',
histogramBase: 0,
}
},
inputs: [],
},
constructor: function() {
this.init = function(context, inputCallback) {
this._context = context;
this._input = inputCallback;
// Define the symbol to be plotted.
// Symbol should be a string.
// You can use PineJS.Std.ticker(this._context) to get the selected symbol's ticker.
// For example,
// var symbol = 'AAPL';
// var symbol = '#EQUITY';
// var symbol = PineJS.Std.ticker(this._context) + '#TEST';
const symbol = '#EQUITY'; // #EQUITY should be replaced with the symbol you want to resolve
this._context.new_sym(symbol, PineJS.Std.period(this._context));
};
this.main = function(context, inputCallback) {
this._context = context;
this._input = inputCallback;
// Select the main symbol
this._context.select_sym(0);
const mainSymbolTime = this._context.new_var(this._context.symbol.time);
// Select the secondary symbol
this._context.select_sym(1);
const secondarySymbolTime = this._context.new_var(this._context.symbol.time);
// Align the times of the secondary symbol to the main symbol
const secondarySymbolClose = this._context.new_var(PineJS.Std.close(this._context));
const alignedClose = secondarySymbolClose.adopt(secondarySymbolTime, mainSymbolTime, 1);
// Select the main symbol again
this._context.select_sym(0);
return [alignedClose];
}
}
}
]);
},
/* Within the Widget constructor options */
custom_indicators_getter: PineJS => {
return Promise.resolve<CustomIndicator[]>([
/* Requesting data for another ticker */
{
name: 'Equity',
metainfo: {
_metainfoVersion: 51,
id: 'Equity@tv-basicstudies-1' as RawStudyMetaInfoId,
description: 'Equity',
shortDescription: 'Equity',
is_price_study: true,
isCustomIndicator: true,
format: {
type: 'price',
// Precision is set to one digit, e.g. 777.7
precision: 1,
},
plots: [{ id: 'plot_0', type: StudyPlotType.Line }],
defaults: {
styles: {
plot_0: {
linestyle: 0,
visible: true,
// Make the line thinner
linewidth: 1,
// Plot type is Line
plottype: 2 as StudyLinePlotPreferences['plottype'],
// Show price line
trackPrice: true,
// Set the plotted line color to dark red
color: '#880000',
},
},
inputs: {},
},
styles: {
plot_0: {
// Output name will be displayed in the Style window
title: 'Equity value',
histogramBase: 0,
},
},
inputs: [],
},
constructor: function (
this: LibraryPineStudy<IPineStudyResult>
) {
this.init = function (context, inputCallback) {
this._context = context;
this._input = inputCallback;
const symbol = '#EQUITY'; // #EQUITY should be replaced with the symbol you want to resolve
this._context.new_sym(
symbol,
PineJS.Std.period(this._context)
);
};
this.main = function (context, inputCallback) {
this._context = context;
this._input = inputCallback;
// Select the main symbol
this._context.select_sym(0);
const mainSymbolTime = this._context.new_var(this._context.symbol.time);
// Select the secondary symbol ("#EQUITY")
this._context.select_sym(1);
const secondarySymbolTime = this._context.new_var(this._context.symbol.time);
// Align the times of the secondary symbol to the main symbol
const secondarySymbolClose = this._context.new_var(PineJS.Std.close(this._context));
const alignedClose = secondarySymbolClose.adopt(secondarySymbolTime, mainSymbolTime, 1);
// Select the main symbol again
this._context.select_sym(0);
return [alignedClose];
};
},
},
]);
},
Coloring Bars
- JavaScript
- TypeScript
custom_indicators_getter: function (PineJS) {
return Promise.resolve([
{
name: 'Bar Colorer Demo',
metainfo: {
_metainfoVersion: 51,
id: "BarColoring@tv-basicstudies-1",
name: "BarColoring",
description: "Bar Colorer Demo",
shortDescription: "Bar Coloring",
isCustomIndicator: true,
is_price_study: true,
format: {
type: 'price',
precision: 4,
},
defaults: {
palettes: {
palette_0: {
// palette colors
// change it to the default colors that you prefer,
// but note that the user can change them in the Style tab
// of indicator properties
colors: [
{ color: '#FFFF00' },
{ color: '#0000FF' }
]
}
}
},
inputs: [],
plots: [{
id: 'plot_0',
// plot type should be set to 'bar_colorer'
type: 'bar_colorer',
// this is the name of the palette that is defined
// in 'palettes' and 'defaults.palettes' sections
palette: 'palette_0'
}],
palettes: {
palette_0: {
colors: [
{ name: 'Color 0' },
{ name: 'Color 1' }
],
// the mapping between the values that
// are returned by the script and palette colors
valToIndex: {
100: 0,
200: 1
}
}
}
},
constructor: function() {
this.main = function(context, input) {
this._context = context;
this._input = input;
var valueForColor0 = 100;
var valueForColor1 = 200;
// perform your calculations here and return one of the constants
// that is specified as a key in 'valToIndex' mapping
var result =
Math.random() * 100 % 2 > 1 ? // we randomly select one of the color values
valueForColor0 : valueForColor1;
return [result];
}
}
}
]);
},
/* Within the Widget constructor options */
custom_indicators_getter: PineJS => {
return Promise.resolve<CustomIndicator[]>([
/* Coloring bars */
{
name: 'Bar Colorer Demo',
metainfo: {
_metainfoVersion: 51,
id: 'BarColoring@tv-basicstudies-1' as RawStudyMetaInfoId,
name: 'BarColoring',
description: 'Bar Colorer Demo',
shortDescription: 'BarColoring',
isCustomIndicator: true,
is_price_study: true,
format: {
type: 'price',
precision: 4,
},
defaults: {
palettes: {
palette_0: {
// palette colors
// change it to the default colors that you prefer,
// but note that the user can change them in the Style tab
// of indicator properties
colors: [{ color: '#FFFF00' }, { color: '#0000FF' }],
},
},
},
inputs: [],
plots: [
{
id: 'plot_0',
// plot type should be set to 'bar_colorer'
type: StudyPlotType.BarColorer,
// this is the name of the palette that is defined
// in 'palettes' and 'defaults.palettes' sections
palette: 'palette_0',
},
],
palettes: {
palette_0: {
colors: [{ name: 'Color 0' }, { name: 'Color 1' }],
// the mapping between the values that
// are returned by the script and palette colors
valToIndex: {
100: 0,
200: 1,
},
},
},
},
constructor: function (
this: LibraryPineStudy<IPineStudyResult>
) {
this.main = function (context, input) {
this._context = context;
this._input = input;
const valueForColor0 = 100;
const valueForColor1 = 200;
// perform your calculations here and return one of the constants
// that is specified as a key in 'valToIndex' mapping
const result =
(Math.random() * 100) % 2 > 1 // we randomly select one of the color values
? valueForColor0
: valueForColor1;
return [result];
};
},
},
]);
},
Custom Styles for Every Point
- JavaScript
- TypeScript
custom_indicators_getter: function(PineJS) {
return Promise.resolve([
{
name: 'Custom Styles For Every Point',
metainfo: {
_metainfoVersion: 51,
id: 'CustomStylesForEveryPoint@tv-basicstudies-1',
description: 'Custom Styles For Every Point',
shortDescription: 'Custom Styles For Every Point',
is_price_study: false,
isCustomIndicator: true,
plots: [
{
'id': 'plot_0',
'type': 'line',
},
{
'id': 'plot_1',
'type': 'colorer',
'target': 'plot_0',
'palette': 'paletteId1',
},
],
palettes: {
paletteId1: {
colors: {
0: {
name: 'First color',
},
1: {
name: 'Second color',
},
},
},
},
defaults: {
palettes: {
paletteId1: {
colors: {
0: {
color: 'red',
width: 1,
style: 0,
},
1: {
color: 'blue',
width: 3,
style: 1,
},
},
},
},
styles: {},
precision: 4,
inputs: {},
},
styles: {
plot_0: {
title: 'Equity value',
histogramBase: 0,
},
},
inputs: [],
format: {
type: 'price',
precision: 4,
},
},
constructor: function() {
this.main = function(context, inputCallback) {
this._context = context;
this._input = inputCallback;
const value = Math.random() * 200;
const colorIndex = value > 100 ? 0 : 1;
return [value, colorIndex];
}
}
}
]);
},
/* Within the Widget constructor options */
custom_indicators_getter: PineJS => {
return Promise.resolve<CustomIndicator[]>([
/* Custom styles for every point */
{
name: 'Custom Styles For Every Point',
metainfo: {
_metainfoVersion: 51,
id: 'CustomStylesForEveryPoint@tv-basicstudies-1' as RawStudyMetaInfoId,
description: 'Custom Styles For Every Point',
shortDescription: 'Custom Styles For Every Point',
is_price_study: false,
isCustomIndicator: true,
plots: [
{
id: 'plot_0',
type: StudyPlotType.Line,
},
{
id: 'plot_1',
type: StudyPlotType.Colorer,
target: 'plot_0',
palette: 'paletteId1',
},
],
palettes: {
paletteId1: {
colors: {
0: {
name: 'First color',
},
1: {
name: 'Second color',
},
},
},
},
defaults: {
palettes: {
paletteId1: {
colors: {
0: {
color: 'red',
width: 1,
style: 0,
},
1: {
color: 'blue',
width: 3,
style: 1,
},
},
},
},
styles: {},
precision: 4,
inputs: {},
},
styles: {
plot_0: {
title: 'Equity value',
histogramBase: 0,
},
},
inputs: [],
format: {
type: 'price',
precision: 4,
},
},
constructor: function (
this: LibraryPineStudy<IPineStudyResult>
) {
this.main = function (context, inputCallback) {
this._context = context;
this._input = inputCallback;
const value = Math.random() * 200;
const colorIndex = value > 100 ? 0 : 1;
return [value, colorIndex];
};
},
},
]);
},
Complex Filled Areas
Advanced Shapes Use
- JavaScript
- TypeScript
custom_indicators_getter: function(PineJS) {
return Promise.resolve([
{
name: 'Mondays',
metainfo: {
_metainfoVersion: 51,
defaults: {
styles: {
plot_0: {
color: '#FF5252',
textColor: '#2196F3',
plottype: 'shape_circle',
location: 'Bottom',
visible: true
}
},
inputs: {}
},
plots: [
{
id: 'plot_0',
type: 'shapes'
}
],
styles: {
plot_0: {
isHidden: false,
location: 'Bottom',
text: 'Monday',
title: 'Shapes'
}
},
description: 'Mondays',
shortDescription: 'Mondays',
is_price_study: true,
inputs: [],
id: 'Mondays@tv-basicstudies-1',
format: {
type: 'inherit',
},
},
constructor: function() {
this.main = function(context, inputCallback) {
// If we don't have a time, then we cannot determine the day of week
if (isNaN(context.symbol.time)) {
return [NaN]
}
// Check if the day of the week is Monday
const dayofweek = PineJS.Std.dayofweek(context);
const shouldBeShapeVisible = dayofweek === 2;
// 1 is plot value, it'll be displayed in legend of the indicator
// NaN means that there is no value for that plot and shape should be hidden for that bar
const plotValue = shouldBeShapeVisible ? 1 : NaN;
return [plotValue];
}
}
},
]);
},
/* Within the Widget constructor options */
custom_indicators_getter: PineJS => {
return Promise.resolve<CustomIndicator[]>([
/* Advanced Shapes use */
{
name: 'Mondays',
metainfo: {
_metainfoVersion: 51,
defaults: {
styles: {
plot_0: {
color: '#FF5252',
textColor: '#2196F3',
plottype: 'shape_circle' as StudyShapesPlotPreferences['plottype'],
location: 'Bottom' as StudyShapesPlotPreferences['location'],
visible: true
}
},
inputs: {},
},
plots: [
{
id: 'plot_0',
type: StudyPlotType.Shapes,
},
],
styles: {
plot_0: {
isHidden: false,
location: 'Bottom' as StudyShapesPlotPreferences['location'],
plottype: 'shape_circle' as StudyShapesPlotPreferences['plottype'],
text: 'Monday',
title: 'Shapes',
},
},
description: 'Mondays',
shortDescription: 'Mondays',
is_price_study: true,
inputs: [],
id: 'Mondays@tv-basicstudies-1' as RawStudyMetaInfoId,
format: {
type: 'inherit',
},
},
constructor: function (
this: LibraryPineStudy<IPineStudyResult>
) {
this.main = function (context, inputCallback) {
// If we don't have a time, then we cannot determine the day of week
if (isNaN(context.symbol.time)) {
return [NaN]
}
// Check if the day of the week is Monday
const dayofweek = PineJS.Std.dayofweek(context);
const shouldBeShapeVisible = dayofweek === 2;
// 1 is plot value, it'll be displayed in legend of the indicator
// NaN means that there is no value for that plot and shape should be hidden for that bar
const plotValue = shouldBeShapeVisible ? 1 : NaN;
return [plotValue];
};
},
},
]);
},
Advanced Colouring Candles
- JavaScript
- TypeScript
custom_indicators_getter: function(PineJS) {
return Promise.resolve([
{
name: 'Advanced Coloring Candles',
metainfo: {
_metainfoVersion: 51,
id: 'advancedcolouringcandles@tv-basicstudies-1',
name: 'Advanced Coloring Candles',
description: 'Advanced Coloring Candles',
shortDescription: 'Advanced Coloring Candles',
isCustomIndicator: true,
is_price_study: false, // whether the study should appear on the main series pane.
linkedToSeries: true, // whether the study price scale should be the same as the main series one.
format: {
type: 'price',
precision: 2,
},
plots: [
{
id: 'plot_open',
type: 'ohlc_open',
target: 'plot_candle',
},
{
id: 'plot_high',
type: 'ohlc_high',
target: 'plot_candle',
},
{
id: 'plot_low',
type: 'ohlc_low',
target: 'plot_candle',
},
{
id: 'plot_close',
type: 'ohlc_close',
target: 'plot_candle',
},
{
id: 'plot_bar_color',
type: 'ohlc_colorer',
palette: 'palette_bar',
target: 'plot_candle',
},
{
id: 'plot_wick_color',
type: 'wick_colorer',
palette: 'palette_wick',
target: 'plot_candle',
},
{
id: 'plot_border_color',
type: 'border_colorer',
palette: 'palette_border',
target: 'plot_candle',
},
],
palettes: {
palette_bar: {
colors: [{ name: 'Colour One' }, { name: 'Colour Two' }],
valToIndex: {
0: 0,
1: 1,
},
},
palette_wick: {
colors: [{ name: 'Colour One' }, { name: 'Colour Two' }],
valToIndex: {
0: 0,
1: 1,
},
},
palette_border: {
colors: [{ name: 'Colour One' }, { name: 'Colour Two' }],
valToIndex: {
0: 0,
1: 1,
},
},
},
ohlcPlots: {
plot_candle: {
title: 'Candles',
},
},
defaults: {
ohlcPlots: {
plot_candle: {
borderColor: '#000000',
color: '#000000',
drawBorder: true,
drawWick: true,
plottype: 'ohlc_candles',
visible: true,
wickColor: '#000000',
},
},
palettes: {
palette_bar: {
colors: [
{ color: '#1948CC', width: 1, style: 0 },
{ color: '#F47D02', width: 1, style: 0 },
],
},
palette_wick: {
colors: [
{ color: '#0C3299', },
{ color: '#E65000', },
],
},
palette_border: {
colors: [
{ color: '#5B9CF6', },
{ color: '#FFB74D', },
],
},
},
precision: 2,
inputs: {},
},
styles: {},
inputs: [],
},
constructor: function () {
this.main = function (context, inputCallback) {
this._context = context;
this._input = inputCallback;
this._context.select_sym(0);
const o = PineJS.Std.open(this._context);
const h = PineJS.Std.high(this._context);
const l = PineJS.Std.low(this._context);
const c = PineJS.Std.close(this._context);
// Color is determined randomly
const colour = Math.round(Math.random());
return [o, h, l, c, colour /*bar*/, colour /*wick*/, colour /*border*/];
};
},
},
]);
},
/* Within the Widget constructor options */
custom_indicators_getter: PineJS => {
return Promise.resolve<CustomIndicator[]>([
/* Advanced Colouring Candles */
{
name: 'Advanced Coloring Candles',
metainfo: {
_metainfoVersion: 51,
id: 'advancedcolouringcandles@tv-basicstudies-1' as RawStudyMetaInfoId,
name: 'Advanced Coloring Candles',
description: 'Advanced Coloring Candles',
shortDescription: 'Advanced Coloring Candles',
isCustomIndicator: true,
is_price_study: false, // whether the study should appear on the main series pane.
linkedToSeries: true, // whether the study price scale should be the same as the main series one.
format: {
type: 'price',
precision: 2,
},
plots: [
{
id: 'plot_open',
type: StudyPlotType.OhlcOpen,
target: 'plot_candle',
},
{
id: 'plot_high',
type: StudyPlotType.OhlcHigh,
target: 'plot_candle',
},
{
id: 'plot_low',
type: StudyPlotType.OhlcLow,
target: 'plot_candle',
},
{
id: 'plot_close',
type: StudyPlotType.OhlcClose,
target: 'plot_candle',
},
{
id: 'plot_bar_color',
type: StudyPlotType.OhlcColorer,
palette: 'palette_bar',
target: 'plot_candle',
},
{
id: 'plot_wick_color',
type: StudyPlotType.CandleWickColorer,
palette: 'palette_wick',
target: 'plot_candle',
},
{
id: 'plot_border_color',
type: StudyPlotType.CandleBorderColorer,
palette: 'palette_border',
target: 'plot_candle',
},
],
palettes: {
palette_bar: {
colors: [{ name: 'Colour One' }, { name: 'Colour Two' }],
valToIndex: {
0: 0,
1: 1,
},
},
palette_wick: {
colors: [{ name: 'Colour One' }, { name: 'Colour Two' }],
valToIndex: {
0: 0,
1: 1,
},
},
palette_border: {
colors: [{ name: 'Colour One' }, { name: 'Colour Two' }],
valToIndex: {
0: 0,
1: 1,
},
},
},
ohlcPlots: {
plot_candle: {
title: 'Candles',
},
},
defaults: {
ohlcPlots: {
plot_candle: {
borderColor: '#000000',
color: '#000000',
drawBorder: true,
drawWick: true,
plottype: OhlcStudyPlotStyle.OhlcCandles,
visible: true,
wickColor: '#000000',
},
},
palettes: {
palette_bar: {
colors: [
{ color: '#1948CC', width: 1, style: 0 },
{ color: '#F47D02', width: 1, style: 0 },
],
},
palette_wick: {
colors: [{ color: '#0C3299' }, { color: '#E65000' }],
},
palette_border: {
colors: [{ color: '#5B9CF6' }, { color: '#FFB74D' }],
},
},
precision: 2,
inputs: {},
},
styles: {},
inputs: [],
},
constructor: function (
this: LibraryPineStudy<IPineStudyResult>
) {
this.main = function (context, inputCallback) {
this._context = context;
this._input = inputCallback;
this._context.select_sym(0);
const o = PineJS.Std.open(this._context);
const h = PineJS.Std.high(this._context);
const l = PineJS.Std.low(this._context);
const c = PineJS.Std.close(this._context);
// Color is determined randomly
const colour = Math.round(Math.random());
return [
o,
h,
l,
c,
colour /*bar*/,
colour /*wick*/,
colour /*border*/,
];
};
},
},
]);
},