- Development:
bun run devornext dev --turbo - Production build:
bun run buildornext build - TypeCheck:
bun run typecheckortsc --noEmit - Lint:
bun run lintornext lint - Format check:
bun run format:checkorprettier --check "**/*.{ts,tsx,js,jsx,mdx}" --cache - Format write:
bun run format:writeorprettier --write "**/*.{ts,tsx,js,jsx,mdx}" --cache - Database:
bun run db:generate,bun run db:migrate,bun run db:push,bun run db:studio
- Imports: Use absolute imports with '@/' alias. Order: project imports first, then third-party
- Naming: camelCase for variables/functions, PascalCase for components, prefix hooks with "use"
- Types: Use explicit TypeScript interfaces/types. Use BigInt for blockchain values. You may never, in any case use "any".
- Components: Function components with explicit prop interfaces, destructuring, conditional rendering
- Styling: Tailwind CSS with class-variance-authority (cva), use
cn()utility for merging classes - Error Handling: Use optional chaining, nullish operators, and conditional rendering
- Web3 Patterns: Wagmi/connectkit for wallet connections, React Query for data fetching
- File Structure: Feature-based organization, _components directories for local components
You may create custom indicators using the TradingView API. Here is an example:
var widget = window.tvWidget = new TradingView.widget({
// ...
custom_indicators_getter: function(PineJS) {
return Promise.resolve([
// Indicator object
{
name: 'Custom Moving Average',
metainfo: {
_metainfoVersion: 53,
id: "Custom Moving Average@tv-basicstudies-1",
description: "Custom Moving Average",
shortDescription: "Custom MA",
format: { type: "inherit" },
linkedToSeries: true,
is_price_study: true,
plots: [
{ id: "plot_0", type: "line" },
{ id: "smoothedMA", type: "line" },
],
defaults: {
styles: {
plot_0: {
linestyle: 0,
linewidth: 1,
plottype: 0,
trackPrice: false,
transparency: 0,
visible: true,
color: "#2196F3",
},
smoothedMA: {
linestyle: 0,
linewidth: 1,
plottype: 0,
trackPrice: false,
transparency: 0,
visible: true,
color: "#9621F3",
},
},
inputs: {
length: 9,
source: "close",
offset: 0,
smoothingLine: "SMA",
smoothingLength: 9,
},
},
styles: {
plot_0: { title: "Plot", histogramBase: 0, joinPoints: true },
smoothedMA: {
title: "Smoothed MA",
histogramBase: 0,
joinPoints: false,
},
},
inputs: [
{
id: "length",
name: "Length",
defval: 9,
type: "integer",
min: 1,
max: 10000,
},
{
id: "source",
name: "Source",
defval: "close",
type: "source",
options: [
"open",
"high",
"low",
"close",
"hl2",
"hlc3",
"ohlc4",
],
},
{
id: "offset",
name: "Offset",
defval: 0,
type: "integer",
min: -10000,
max: 10000,
},
{
id: "smoothingLine",
name: "Smoothing Line",
defval: "SMA",
type: "text",
options: ["SMA", "EMA", "WMA"],
},
{
id: "smoothingLength",
name: "Smoothing Length",
defval: 9,
type: "integer",
min: 1,
max: 10000,
},
],
},
constructor: function () {
this.main = function (ctx, inputs) {
this._context = ctx;
this._input = inputs;
var length = this._input(0);
var offset = this._input(2);
var smoothingLine = this._input(3);
var smoothingLength = this._input(4);
var source = PineJS.Std[this._input(1)](this._context);
this._context.setMinimumAdditionalDepth(length + smoothingLength);
var series = this._context.new_var(source);
var sma = PineJS.Std.sma(series, length, this._context);
var sma_series = this._context.new_var(sma);
var smoothedMA;
if (smoothingLine === "EMA") {
smoothedMA = PineJS.Std.ema(
sma_series,
smoothingLength,
this._context
);
} else if (smoothingLine === "WMA") {
smoothedMA = PineJS.Std.wma(
sma_series,
smoothingLength,
this._context
);
} else { // if (smoothingLine === "SMA") {
smoothedMA = PineJS.Std.sma(
sma_series,
smoothingLength,
this._context
);
}
return [
{ value: sma, offset: offset },
{ value: smoothedMA, offset: offset },
];
};
},
}
]);
},
});