@mathieuc/tradingview 3.5.2 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +112 -51
  2. package/dist/chart/chart-session.d.ts +114 -0
  3. package/dist/chart/chart-session.js +339 -0
  4. package/dist/chart/graphics.d.ts +129 -0
  5. package/dist/chart/graphics.js +153 -0
  6. package/dist/chart/index.d.ts +11 -0
  7. package/dist/chart/index.js +6 -0
  8. package/dist/chart/strategy.d.ts +113 -0
  9. package/dist/chart/strategy.js +78 -0
  10. package/dist/chart/study.d.ts +60 -0
  11. package/dist/chart/study.js +179 -0
  12. package/dist/chart/timeframes.d.ts +7 -0
  13. package/dist/chart/timeframes.js +22 -0
  14. package/dist/chart/types.d.ts +105 -0
  15. package/dist/chart/types.js +9 -0
  16. package/dist/client/client.d.ts +89 -0
  17. package/dist/client/client.js +254 -0
  18. package/dist/client/index.d.ts +4 -0
  19. package/dist/client/index.js +2 -0
  20. package/dist/client/transport.d.ts +27 -0
  21. package/dist/client/transport.js +38 -0
  22. package/dist/data/candles.d.ts +40 -0
  23. package/dist/data/candles.js +101 -0
  24. package/dist/data/history.d.ts +61 -0
  25. package/dist/data/history.js +101 -0
  26. package/dist/data/index.d.ts +30 -0
  27. package/dist/data/index.js +16 -0
  28. package/dist/data/indicators.d.ts +54 -0
  29. package/dist/data/indicators.js +139 -0
  30. package/dist/data/operation.d.ts +71 -0
  31. package/dist/data/operation.js +205 -0
  32. package/dist/data/provider.d.ts +23 -0
  33. package/dist/data/provider.js +11 -0
  34. package/dist/data/quotes.d.ts +33 -0
  35. package/dist/data/quotes.js +117 -0
  36. package/dist/data/symbols.d.ts +9 -0
  37. package/dist/data/symbols.js +19 -0
  38. package/dist/errors.d.ts +53 -0
  39. package/dist/errors.js +24 -0
  40. package/dist/events.d.ts +36 -0
  41. package/dist/events.js +70 -0
  42. package/dist/http/account.d.ts +47 -0
  43. package/dist/http/account.js +127 -0
  44. package/dist/http/index.d.ts +11 -0
  45. package/dist/http/index.js +5 -0
  46. package/dist/http/indicators.d.ts +37 -0
  47. package/dist/http/indicators.js +144 -0
  48. package/dist/http/layouts.d.ts +36 -0
  49. package/dist/http/layouts.js +24 -0
  50. package/dist/http/market.d.ts +45 -0
  51. package/dist/http/market.js +59 -0
  52. package/dist/http/pine-permissions.d.ts +29 -0
  53. package/dist/http/pine-permissions.js +56 -0
  54. package/dist/http/request.d.ts +44 -0
  55. package/dist/http/request.js +83 -0
  56. package/dist/index.d.ts +21 -0
  57. package/dist/index.js +19 -0
  58. package/dist/indicators/builtin-indicator.d.ts +17 -0
  59. package/dist/indicators/builtin-indicator.js +75 -0
  60. package/dist/indicators/index.d.ts +8 -0
  61. package/dist/indicators/index.js +2 -0
  62. package/dist/indicators/pine-indicator.d.ts +63 -0
  63. package/dist/indicators/pine-indicator.js +101 -0
  64. package/dist/protocol/compression.d.ts +12 -0
  65. package/dist/protocol/compression.js +83 -0
  66. package/dist/protocol/framing.d.ts +59 -0
  67. package/dist/protocol/framing.js +68 -0
  68. package/dist/protocol/ids.d.ts +2 -0
  69. package/dist/protocol/ids.js +10 -0
  70. package/dist/protocol/index.d.ts +4 -0
  71. package/dist/protocol/index.js +3 -0
  72. package/dist/quote/fields.d.ts +35 -0
  73. package/dist/quote/fields.js +21 -0
  74. package/dist/quote/index.d.ts +4 -0
  75. package/dist/quote/index.js +2 -0
  76. package/dist/quote/quote-session.d.ts +73 -0
  77. package/dist/quote/quote-session.js +205 -0
  78. package/docs/README.es.md +58 -0
  79. package/docs/README.fr.md +58 -0
  80. package/docs/README.pt.md +58 -0
  81. package/docs/data-api.md +285 -0
  82. package/docs/low-level-api.md +213 -0
  83. package/docs/migration-v4.md +128 -0
  84. package/docs/release-4.0.0-beta.1.md +39 -0
  85. package/docs/v4-coverage.md +213 -0
  86. package/package.json +53 -20
  87. package/.env.sample +0 -2
  88. package/.eslintrc.js +0 -28
  89. package/.gitattributes +0 -2
  90. package/docs/DOCS.md +0 -3
  91. package/examples/AllPrivateIndicators.js +0 -44
  92. package/examples/BuiltInIndicator.js +0 -51
  93. package/examples/CustomChartType.js +0 -123
  94. package/examples/CustomTimeframe.js +0 -31
  95. package/examples/Errors.js +0 -155
  96. package/examples/FakeReplayMode.js +0 -40
  97. package/examples/FromToData.js +0 -35
  98. package/examples/GetDrawings.js +0 -27
  99. package/examples/GraphicIndicator.js +0 -42
  100. package/examples/MultipleSyncFetch.js +0 -44
  101. package/examples/PinePermManage.js +0 -67
  102. package/examples/ReplayMode.js +0 -103
  103. package/examples/Search.js +0 -14
  104. package/examples/SimpleChart.js +0 -63
  105. package/examples/UserLogin.js +0 -16
  106. package/main.js +0 -11
  107. package/src/chart/graphicParser.js +0 -308
  108. package/src/chart/session.js +0 -553
  109. package/src/chart/study.js +0 -435
  110. package/src/classes/BuiltInIndicator.js +0 -137
  111. package/src/classes/PineIndicator.js +0 -132
  112. package/src/classes/PinePermManager.js +0 -159
  113. package/src/client.js +0 -298
  114. package/src/miscRequests.js +0 -609
  115. package/src/protocol.js +0 -60
  116. package/src/quote/market.js +0 -132
  117. package/src/quote/session.js +0 -125
  118. package/src/types.js +0 -36
  119. package/src/utils.js +0 -20
  120. package/vite.config.js +0 -7
@@ -0,0 +1,129 @@
1
+ /** Raw graphics as sent by TradingView, indexed by type then drawing ID. */
2
+ export type RawGraphics = Record<string, Record<string, any>>;
3
+ export type ExtendValue = 'right' | 'left' | 'both' | 'none';
4
+ export type YLocValue = 'price' | 'abovebar' | 'belowbar';
5
+ export type LabelStyleValue = 'none' | 'xcross' | 'cross' | 'triangleup' | 'triangledown' | 'flag' | 'circle' | 'arrowup' | 'arrowdown' | 'label_up' | 'label_down' | 'label_left' | 'label_right' | 'label_lower_left' | 'label_lower_right' | 'label_upper_left' | 'label_upper_right' | 'label_center' | 'square' | 'diamond';
6
+ export type LineStyleValue = 'solid' | 'dotted' | 'dashed' | 'arrow_left' | 'arrow_right' | 'arrow_both';
7
+ export type BoxStyleValue = 'solid' | 'dotted' | 'dashed';
8
+ export type SizeValue = 'auto' | 'huge' | 'large' | 'normal' | 'small' | 'tiny';
9
+ export type VAlignValue = 'top' | 'center' | 'bottom';
10
+ export type HAlignValue = 'left' | 'center' | 'right';
11
+ export type TextWrapValue = 'none' | 'auto';
12
+ export type TablePositionValue = 'top_left' | 'top_center' | 'top_right' | 'middle_left' | 'middle_center' | 'middle_right' | 'bottom_left' | 'bottom_center' | 'bottom_right';
13
+ /**
14
+ * X positions are expressed in bars back from the most recent bar loaded on
15
+ * the chart (0 = latest bar). They are `undefined` when the bar is not loaded.
16
+ */
17
+ export interface GraphicLabel {
18
+ id: number;
19
+ x: number | undefined;
20
+ y: number;
21
+ yLoc: YLocValue;
22
+ text: string;
23
+ style: LabelStyleValue;
24
+ color: number;
25
+ textColor: number;
26
+ size: SizeValue;
27
+ textAlign: HAlignValue;
28
+ toolTip: string;
29
+ }
30
+ export interface GraphicLine {
31
+ id: number;
32
+ x1: number | undefined;
33
+ y1: number;
34
+ x2: number | undefined;
35
+ y2: number;
36
+ extend: ExtendValue;
37
+ style: LineStyleValue;
38
+ color: number;
39
+ width: number;
40
+ }
41
+ export interface GraphicBox {
42
+ id: number;
43
+ x1: number | undefined;
44
+ y1: number;
45
+ x2: number | undefined;
46
+ y2: number;
47
+ color: number;
48
+ bgColor: number;
49
+ extend: ExtendValue;
50
+ style: BoxStyleValue;
51
+ width: number;
52
+ text: string;
53
+ textSize: SizeValue;
54
+ textColor: number;
55
+ textVAlign: VAlignValue;
56
+ textHAlign: HAlignValue;
57
+ textWrap: TextWrapValue;
58
+ }
59
+ export interface TableCell {
60
+ id: number;
61
+ text: string;
62
+ width: number;
63
+ height: number;
64
+ textColor: number;
65
+ textHAlign: HAlignValue;
66
+ textVAlign: VAlignValue;
67
+ textSize: SizeValue;
68
+ bgColor: number;
69
+ }
70
+ export interface GraphicTable {
71
+ id: number;
72
+ position: TablePositionValue;
73
+ rows: number;
74
+ columns: number;
75
+ bgColor: number;
76
+ frameColor: number;
77
+ frameWidth: number;
78
+ borderColor: number;
79
+ borderWidth: number;
80
+ /** Cells as a `[row][column]` matrix. */
81
+ cells: TableCell[][];
82
+ }
83
+ export interface GraphicHorizLine {
84
+ id: number;
85
+ level: number;
86
+ startIndex: number | undefined;
87
+ endIndex: number | undefined;
88
+ extendRight: boolean;
89
+ extendLeft: boolean;
90
+ [key: string]: unknown;
91
+ }
92
+ export interface GraphicPoint {
93
+ index: number | undefined;
94
+ level: number;
95
+ [key: string]: unknown;
96
+ }
97
+ export interface GraphicPolygon {
98
+ id: number;
99
+ points: GraphicPoint[];
100
+ [key: string]: unknown;
101
+ }
102
+ export interface GraphicHorizHist {
103
+ id: number;
104
+ priceLow: number;
105
+ priceHigh: number;
106
+ firstBarTime: number | undefined;
107
+ lastBarTime: number | undefined;
108
+ rate: number[];
109
+ [key: string]: unknown;
110
+ }
111
+ /** Drawings produced by an indicator, grouped by type. */
112
+ export interface GraphicsData {
113
+ labels: GraphicLabel[];
114
+ lines: GraphicLine[];
115
+ boxes: GraphicBox[];
116
+ tables: GraphicTable[];
117
+ polygons: GraphicPolygon[];
118
+ horizLines: GraphicHorizLine[];
119
+ horizHists: GraphicHorizHist[];
120
+ /** Unparsed graphics, including types this parser does not know. */
121
+ raw: RawGraphics;
122
+ }
123
+ /**
124
+ * Converts raw indicator graphics into readable objects.
125
+ * @param indexes Maps graphic X indexes to "bars back" positions.
126
+ */
127
+ export declare function parseGraphics(raw?: RawGraphics, indexes?: ReadonlyArray<number | undefined>): GraphicsData;
128
+ /** Applies `graphicsCmds` (erase then create) to raw graphics in place. */
129
+ export declare function applyGraphicsCommands(graphics: RawGraphics, commands: any): void;
@@ -0,0 +1,153 @@
1
+ const TRANSLATOR = {
2
+ extend: {
3
+ r: 'right', l: 'left', b: 'both', n: 'none',
4
+ },
5
+ yLoc: { pr: 'price', ab: 'abovebar', bl: 'belowbar' },
6
+ labelStyle: {
7
+ n: 'none',
8
+ xcr: 'xcross',
9
+ cr: 'cross',
10
+ tup: 'triangleup',
11
+ tdn: 'triangledown',
12
+ flg: 'flag',
13
+ cir: 'circle',
14
+ aup: 'arrowup',
15
+ adn: 'arrowdown',
16
+ lup: 'label_up',
17
+ ldn: 'label_down',
18
+ llf: 'label_left',
19
+ lrg: 'label_right',
20
+ llwlf: 'label_lower_left',
21
+ llwrg: 'label_lower_right',
22
+ luplf: 'label_upper_left',
23
+ luprg: 'label_upper_right',
24
+ lcn: 'label_center',
25
+ sq: 'square',
26
+ dia: 'diamond',
27
+ },
28
+ lineStyle: {
29
+ sol: 'solid', dot: 'dotted', dsh: 'dashed', al: 'arrow_left', ar: 'arrow_right', ab: 'arrow_both',
30
+ },
31
+ boxStyle: { sol: 'solid', dot: 'dotted', dsh: 'dashed' },
32
+ };
33
+ /**
34
+ * Converts raw indicator graphics into readable objects.
35
+ * @param indexes Maps graphic X indexes to "bars back" positions.
36
+ */
37
+ export function parseGraphics(raw = {}, indexes = []) {
38
+ const values = (type) => Object.values(raw[type] ?? {});
39
+ const x = (index) => indexes[index];
40
+ return {
41
+ labels: values('dwglabels').map((l) => ({
42
+ id: l.id,
43
+ x: x(l.x),
44
+ y: l.y,
45
+ yLoc: TRANSLATOR.yLoc[l.yl] ?? l.yl,
46
+ text: l.t,
47
+ style: TRANSLATOR.labelStyle[l.st] ?? l.st,
48
+ color: l.ci,
49
+ textColor: l.tci,
50
+ size: l.sz,
51
+ textAlign: l.ta,
52
+ toolTip: l.tt,
53
+ })),
54
+ lines: values('dwglines').map((l) => ({
55
+ id: l.id,
56
+ x1: x(l.x1),
57
+ y1: l.y1,
58
+ x2: x(l.x2),
59
+ y2: l.y2,
60
+ extend: TRANSLATOR.extend[l.ex] ?? l.ex,
61
+ style: TRANSLATOR.lineStyle[l.st] ?? l.st,
62
+ color: l.ci,
63
+ width: l.w,
64
+ })),
65
+ boxes: values('dwgboxes').map((b) => ({
66
+ id: b.id,
67
+ x1: x(b.x1),
68
+ y1: b.y1,
69
+ x2: x(b.x2),
70
+ y2: b.y2,
71
+ color: b.c,
72
+ bgColor: b.bc,
73
+ extend: TRANSLATOR.extend[b.ex] ?? b.ex,
74
+ style: TRANSLATOR.boxStyle[b.st] ?? b.st,
75
+ width: b.w,
76
+ text: b.t,
77
+ textSize: b.ts,
78
+ textColor: b.tc,
79
+ textVAlign: b.tva,
80
+ textHAlign: b.tha,
81
+ textWrap: b.tw,
82
+ })),
83
+ tables: values('dwgtables').map((t) => {
84
+ const cells = [];
85
+ for (const cell of values('dwgtablecells')) {
86
+ if (cell.tid !== t.id)
87
+ continue;
88
+ cells[cell.row] ??= [];
89
+ cells[cell.row][cell.col] = {
90
+ id: cell.id,
91
+ text: cell.t,
92
+ width: cell.w,
93
+ height: cell.h,
94
+ textColor: cell.tc,
95
+ textHAlign: cell.tha,
96
+ textVAlign: cell.tva,
97
+ textSize: cell.ts,
98
+ bgColor: cell.bgc,
99
+ };
100
+ }
101
+ return {
102
+ id: t.id,
103
+ position: t.pos,
104
+ rows: t.rows,
105
+ columns: t.cols,
106
+ bgColor: t.bgc,
107
+ frameColor: t.frmc,
108
+ frameWidth: t.frmw,
109
+ borderColor: t.brdc,
110
+ borderWidth: t.brdw,
111
+ cells,
112
+ };
113
+ }),
114
+ horizLines: values('horizlines').map((h) => ({
115
+ ...h,
116
+ startIndex: x(h.startIndex),
117
+ endIndex: x(h.endIndex),
118
+ })),
119
+ polygons: values('polygons').map((p) => ({
120
+ ...p,
121
+ points: (p.points ?? []).map((point) => ({ ...point, index: x(point.index) })),
122
+ })),
123
+ horizHists: values('hhists').map((h) => ({
124
+ ...h,
125
+ firstBarTime: x(h.firstBarTime),
126
+ lastBarTime: x(h.lastBarTime),
127
+ })),
128
+ raw,
129
+ };
130
+ }
131
+ /** Applies `graphicsCmds` (erase then create) to raw graphics in place. */
132
+ export function applyGraphicsCommands(graphics, commands) {
133
+ for (const instruction of commands?.erase ?? []) {
134
+ if (instruction.action === 'all') {
135
+ if (!instruction.type) {
136
+ for (const type of Object.keys(graphics))
137
+ graphics[type] = {};
138
+ }
139
+ else
140
+ delete graphics[instruction.type];
141
+ }
142
+ else if (instruction.action === 'one' && instruction.type) {
143
+ delete graphics[instruction.type]?.[instruction.id];
144
+ }
145
+ }
146
+ for (const [type, groups] of Object.entries(commands?.create ?? {})) {
147
+ graphics[type] ??= {};
148
+ for (const group of groups ?? []) {
149
+ for (const item of group.data ?? [])
150
+ graphics[type][item.id] = item;
151
+ }
152
+ }
153
+ }
@@ -0,0 +1,11 @@
1
+ export { ChartSession } from './chart-session.js';
2
+ export type { ChartEvents, MarketOptions, SeriesCompletedInfo, } from './chart-session.js';
3
+ export { Study } from './study.js';
4
+ export type { StudyChange, StudyEvents, StudyValue } from './study.js';
5
+ export { applyGraphicsCommands, parseGraphics, } from './graphics.js';
6
+ export type { BoxStyleValue, ExtendValue, GraphicBox, GraphicHorizHist, GraphicHorizLine, GraphicLabel, GraphicLine, GraphicPoint, GraphicPolygon, GraphicTable, GraphicsData, HAlignValue, LabelStyleValue, LineStyleValue, RawGraphics, SizeValue, TableCell, TablePositionValue, TextWrapValue, VAlignValue, YLocValue, } from './graphics.js';
7
+ export { mergeStrategyReport, parseTrades, summarizeStrategyReport } from './strategy.js';
8
+ export type { FromTo, PerformanceReport, RelAbsValue, StrategyReport, StrategyReportChange, StrategySummary, TradeReport, } from './strategy.js';
9
+ export { timeframeSeconds } from './timeframes.js';
10
+ export { CHART_TYPE_STUDIES } from './types.js';
11
+ export type { Adjustment, Candle, ChartType, ChartTypeInputs, MarketSymbol, Subsession, SymbolInfo, Timeframe, Timezone, TradingSession, } from './types.js';
@@ -0,0 +1,6 @@
1
+ export { ChartSession } from './chart-session.js';
2
+ export { Study } from './study.js';
3
+ export { applyGraphicsCommands, parseGraphics, } from './graphics.js';
4
+ export { mergeStrategyReport, parseTrades, summarizeStrategyReport } from './strategy.js';
5
+ export { timeframeSeconds } from './timeframes.js';
6
+ export { CHART_TYPE_STUDIES } from './types.js';
@@ -0,0 +1,113 @@
1
+ /** A value with absolute and percent forms. */
2
+ export interface RelAbsValue {
3
+ v: number;
4
+ p: number;
5
+ }
6
+ export interface TradeReport {
7
+ entry: {
8
+ name: string;
9
+ type: 'long' | 'short';
10
+ value: number;
11
+ time: number;
12
+ };
13
+ /** `name` is '' for exits that are not explicit. */
14
+ exit: {
15
+ name: string;
16
+ value: number;
17
+ time: number;
18
+ };
19
+ quantity: number;
20
+ profit: RelAbsValue;
21
+ cumulative: RelAbsValue;
22
+ runup: RelAbsValue;
23
+ drawdown: RelAbsValue;
24
+ }
25
+ export interface PerformanceReport {
26
+ avgBarsInTrade: number;
27
+ avgBarsInWinTrade: number;
28
+ avgBarsInLossTrade: number;
29
+ avgTrade: number;
30
+ avgTradePercent: number;
31
+ avgLosTrade: number;
32
+ avgLosTradePercent: number;
33
+ avgWinTrade: number;
34
+ avgWinTradePercent: number;
35
+ commissionPaid: number;
36
+ grossLoss: number;
37
+ grossLossPercent: number;
38
+ grossProfit: number;
39
+ grossProfitPercent: number;
40
+ largestLosTrade: number;
41
+ largestLosTradePercent: number;
42
+ largestWinTrade: number;
43
+ largestWinTradePercent: number;
44
+ marginCalls: number;
45
+ maxContractsHeld: number;
46
+ netProfit: number;
47
+ netProfitPercent: number;
48
+ numberOfLosingTrades: number;
49
+ numberOfWiningTrades: number;
50
+ percentProfitable: number;
51
+ profitFactor: number;
52
+ ratioAvgWinAvgLoss: number;
53
+ totalOpenTrades: number;
54
+ totalTrades: number;
55
+ [key: string]: number;
56
+ }
57
+ export interface FromTo {
58
+ from: number;
59
+ to: number;
60
+ }
61
+ /** Report sent by Pine strategies (backtest results computed by TradingView). */
62
+ export interface StrategyReport {
63
+ currency?: string;
64
+ settings?: {
65
+ dateRange?: {
66
+ backtest?: FromTo;
67
+ trade?: FromTo;
68
+ };
69
+ [key: string]: unknown;
70
+ };
71
+ /** Trade records, most recent first; may include open positions with an exit valuation. */
72
+ trades: TradeReport[];
73
+ history: {
74
+ buyHold?: number[];
75
+ buyHoldPercent?: number[];
76
+ drawDown?: number[];
77
+ drawDownPercent?: number[];
78
+ equity?: number[];
79
+ equityPercent?: number[];
80
+ };
81
+ performance: {
82
+ all?: PerformanceReport;
83
+ long?: PerformanceReport;
84
+ short?: PerformanceReport;
85
+ buyHoldReturn?: number;
86
+ buyHoldReturnPercent?: number;
87
+ maxDrawDown?: number;
88
+ maxDrawDownPercent?: number;
89
+ openPL?: number;
90
+ openPLPercent?: number;
91
+ sharpeRatio?: number;
92
+ sortinoRatio?: number;
93
+ [key: string]: unknown;
94
+ };
95
+ }
96
+ export type StrategyReportChange = 'report.currency' | 'report.settings' | 'report.perf' | 'report.trades' | 'report.history';
97
+ /** Converts raw trades (oldest first) into readable trades (most recent first). */
98
+ export declare function parseTrades(trades: any[]): TradeReport[];
99
+ /** Merges a raw report into `target`; returns the changed parts. */
100
+ export declare function mergeStrategyReport(target: StrategyReport, report: any): StrategyReportChange[];
101
+ /** Aggregate counts are authoritative; an exit valuation does not prove closure. */
102
+ export interface StrategySummary {
103
+ tradeRecordCount: number;
104
+ closedTradeCount?: number;
105
+ openTradeCount?: number;
106
+ closedNetProfit?: number;
107
+ openPnL?: number;
108
+ /** Available only when both closed and open PnL are present. */
109
+ totalPnL?: number;
110
+ currency?: string;
111
+ }
112
+ /** Summarizes reported aggregates without inferring missing values or trade status. */
113
+ export declare function summarizeStrategyReport(report: StrategyReport): StrategySummary;
@@ -0,0 +1,78 @@
1
+ import { TradingViewError } from '../errors.js';
2
+ /** Converts raw trades (oldest first) into readable trades (most recent first). */
3
+ export function parseTrades(trades) {
4
+ if (!Array.isArray(trades) || trades.some((trade) => !trade || typeof trade !== 'object' || Array.isArray(trade))) {
5
+ throw new TradingViewError('PARSE_ERROR', 'Strategy trades must be an array of records');
6
+ }
7
+ return [...trades].reverse().map((t) => ({
8
+ entry: {
9
+ name: t.e?.c,
10
+ type: String(t.e?.tp ?? '').startsWith('s') ? 'short' : 'long',
11
+ value: t.e?.p,
12
+ time: t.e?.tm,
13
+ },
14
+ exit: { name: t.x?.c, value: t.x?.p, time: t.x?.tm },
15
+ quantity: t.q,
16
+ profit: t.tp,
17
+ cumulative: t.cp,
18
+ runup: t.rn,
19
+ drawdown: t.dd,
20
+ }));
21
+ }
22
+ /** Merges a raw report into `target`; returns the changed parts. */
23
+ export function mergeStrategyReport(target, report) {
24
+ const changes = [];
25
+ if (!report || typeof report !== 'object')
26
+ return changes;
27
+ // Parse before mutating the target so a malformed trade list cannot leave a partial merge.
28
+ const trades = report.trades === undefined ? undefined : parseTrades(report.trades);
29
+ if (report.currency) {
30
+ target.currency = report.currency;
31
+ changes.push('report.currency');
32
+ }
33
+ if (report.settings) {
34
+ target.settings = report.settings;
35
+ changes.push('report.settings');
36
+ }
37
+ if (report.performance) {
38
+ target.performance = report.performance;
39
+ changes.push('report.perf');
40
+ }
41
+ if (trades !== undefined) {
42
+ target.trades = trades;
43
+ changes.push('report.trades');
44
+ }
45
+ const historyKeys = [
46
+ 'buyHold', 'buyHoldPercent', 'drawDown', 'drawDownPercent', 'equity', 'equityPercent',
47
+ ];
48
+ let historyChanged = false;
49
+ for (const key of historyKeys) {
50
+ if (Array.isArray(report[key])) {
51
+ target.history[key] = report[key];
52
+ historyChanged = true;
53
+ }
54
+ }
55
+ if (historyChanged)
56
+ changes.push('report.history');
57
+ return changes;
58
+ }
59
+ /** Summarizes reported aggregates without inferring missing values or trade status. */
60
+ export function summarizeStrategyReport(report) {
61
+ const finite = (value) => typeof value === 'number' && Number.isFinite(value) ? value : undefined;
62
+ const count = (value) => {
63
+ const n = finite(value);
64
+ return n !== undefined && Number.isInteger(n) && n >= 0 ? n : undefined;
65
+ };
66
+ const closedNetProfit = finite(report.performance.all?.netProfit);
67
+ const openPnL = finite(report.performance.openPL);
68
+ return {
69
+ currency: report.currency,
70
+ tradeRecordCount: report.trades.length,
71
+ closedTradeCount: count(report.performance.all?.totalTrades),
72
+ openTradeCount: count(report.performance.all?.totalOpenTrades),
73
+ closedNetProfit,
74
+ openPnL,
75
+ totalPnL: closedNetProfit !== undefined && openPnL !== undefined
76
+ ? finite(closedNetProfit + openPnL) : undefined,
77
+ };
78
+ }
@@ -0,0 +1,60 @@
1
+ import { TradingViewError } from '../errors.js';
2
+ import { Emitter } from '../events.js';
3
+ import type { Indicator } from '../indicators/index.js';
4
+ import type { ServerPacket } from '../protocol/framing.js';
5
+ import { type GraphicsData } from './graphics.js';
6
+ import { type StrategyReport, type StrategyReportChange } from './strategy.js';
7
+ /** One study row: `$time` (Unix seconds) plus one entry per plot. */
8
+ export interface StudyValue {
9
+ $time: number;
10
+ [plot: string]: number;
11
+ }
12
+ export type StudyChange = 'plots' | 'graphic' | StrategyReportChange;
13
+ export interface StudyEvents {
14
+ [event: string]: unknown[];
15
+ /** The server started (re)computing the study. */
16
+ loading: [];
17
+ /** The study finished computing over the loaded bars. */
18
+ ready: [];
19
+ update: [changes: StudyChange[]];
20
+ error: [error: TradingViewError];
21
+ }
22
+ /** @internal Link between a study and its chart. */
23
+ export interface StudyBridge {
24
+ chartId: string;
25
+ send(method: string, params: unknown[]): void;
26
+ barsBack(): Map<number, number>;
27
+ log(...args: unknown[]): void;
28
+ unregister(id: string): void;
29
+ }
30
+ /** An indicator running on a chart. Create it with `chart.createStudy(indicator)`. */
31
+ export declare class Study extends Emitter<StudyEvents> {
32
+ #private;
33
+ readonly id: string;
34
+ /** @internal Use `chart.createStudy()`. */
35
+ constructor(bridge: StudyBridge, indicator: Indicator);
36
+ /** @internal */
37
+ create(): void;
38
+ /** The indicator definition running in this study. */
39
+ get indicator(): Indicator;
40
+ /** True after the first `study_completed`. */
41
+ get isReady(): boolean;
42
+ /** True after `remove()` or when the chart is gone. */
43
+ get isRemoved(): boolean;
44
+ /** Plot values, oldest first. */
45
+ get values(): StudyValue[];
46
+ /** Drawings (labels, lines, boxes, tables...) produced by the indicator. */
47
+ get graphics(): GraphicsData;
48
+ /** Strategy report (Pine strategies only). */
49
+ get strategyReport(): StrategyReport;
50
+ /** Replaces the indicator (typically the same script with new inputs). */
51
+ setIndicator(indicator: Indicator): void;
52
+ /** Removes the study from the chart. Idempotent. */
53
+ remove(): void;
54
+ /** @internal Called when the chart or connection is gone; `error` is reported if set. */
55
+ dispose(error?: TradingViewError): void;
56
+ /** @internal Packets addressed to this study (`study_*`). */
57
+ onPacket(packet: ServerPacket): void;
58
+ /** @internal Data from `timescale_update` / `du`. */
59
+ onData(data: any): void;
60
+ }