@tradecanvas/svelte 1.0.15 → 1.2.0
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.
- package/README.md +1 -1
- package/dist/TradeCanvas.svelte +53 -26
- package/dist/TradeCanvas.svelte.d.ts +9 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Streams live Binance data by default. Pass `data={bars}` for static OHLC, or `ad
|
|
|
35
35
|
|
|
36
36
|
## Props
|
|
37
37
|
|
|
38
|
-
`symbol`, `timeframe`, `theme`, `chartType`, `indicators
|
|
38
|
+
`symbol`, `timeframe`, `theme`, `chartType`, `indicators` (ids, or `{ id, params, position }`), `data` (bars of your own; no stream), `adapter`, `stream` (`false`: no stream of its own), `historyLimit`, `features` (changes apply after mount too), `autoScale`, `signalMarkers`, `signalMarkerStyle`, `tradeZones`, `tradeZoneStyle`, `overrides` (style overrides by key, all of your app's), `watermarkText`, `onReady`, and `bind:chart`.
|
|
39
39
|
|
|
40
40
|
Reach the underlying `Chart` (drawings, trading, execution adapters, plugins, resizable panes) via `bind:chart` or `onReady`. See the [main docs](https://github.com/bonguynvan/tradecanvas).
|
|
41
41
|
|
package/dist/TradeCanvas.svelte
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
BinanceAdapter,
|
|
6
6
|
DARK_THEME,
|
|
7
7
|
LIGHT_THEME,
|
|
8
|
+
syncIndicators,
|
|
8
9
|
} from '@tradecanvas/chart';
|
|
9
10
|
import type {
|
|
10
11
|
ChartType,
|
|
@@ -17,6 +18,8 @@
|
|
|
17
18
|
SignalMarkerStyle,
|
|
18
19
|
TradeZoneStyle,
|
|
19
20
|
DataAdapter,
|
|
21
|
+
ChartStyleOverrides,
|
|
22
|
+
IndicatorSpec,
|
|
20
23
|
} from '@tradecanvas/chart';
|
|
21
24
|
|
|
22
25
|
interface Props {
|
|
@@ -24,16 +27,23 @@
|
|
|
24
27
|
timeframe?: TimeFrame;
|
|
25
28
|
theme?: 'dark' | 'light' | Theme;
|
|
26
29
|
chartType?: ChartType;
|
|
27
|
-
|
|
30
|
+
/** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */
|
|
31
|
+
indicators?: IndicatorSpec[];
|
|
32
|
+
/** Static bars: the chart shows these, and opens no stream of its own when it has them at mount. */
|
|
28
33
|
data?: OHLCBar[];
|
|
29
34
|
adapter?: DataAdapter;
|
|
35
|
+
/** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */
|
|
36
|
+
stream?: boolean;
|
|
30
37
|
historyLimit?: number;
|
|
38
|
+
/** What users can do on the chart; changes after mount are applied too (the keys given). */
|
|
31
39
|
features?: FeaturesConfig;
|
|
32
40
|
autoScale?: boolean;
|
|
33
41
|
signalMarkers?: SignalMarker[];
|
|
34
42
|
signalMarkerStyle?: SignalMarkerStyle;
|
|
35
43
|
tradeZones?: TradeZone[];
|
|
36
44
|
tradeZoneStyle?: TradeZoneStyle;
|
|
45
|
+
/** Style overrides, by key: all of your app's (`chart.setOverrides`). */
|
|
46
|
+
overrides?: ChartStyleOverrides;
|
|
37
47
|
watermarkText?: string;
|
|
38
48
|
onReady?: (chart: Chart) => void;
|
|
39
49
|
chart?: Chart | null;
|
|
@@ -44,9 +54,10 @@
|
|
|
44
54
|
timeframe = '5m' as TimeFrame,
|
|
45
55
|
theme = 'dark' as 'dark' | 'light' | Theme,
|
|
46
56
|
chartType = 'candlestick' as ChartType,
|
|
47
|
-
indicators = [] as
|
|
57
|
+
indicators = [] as IndicatorSpec[],
|
|
48
58
|
data = undefined as OHLCBar[] | undefined,
|
|
49
59
|
adapter = undefined as DataAdapter | undefined,
|
|
60
|
+
stream = true,
|
|
50
61
|
historyLimit = 500,
|
|
51
62
|
features = undefined as FeaturesConfig | undefined,
|
|
52
63
|
autoScale = true,
|
|
@@ -54,6 +65,7 @@
|
|
|
54
65
|
signalMarkerStyle = undefined as SignalMarkerStyle | undefined,
|
|
55
66
|
tradeZones = undefined as TradeZone[] | undefined,
|
|
56
67
|
tradeZoneStyle = undefined as TradeZoneStyle | undefined,
|
|
68
|
+
overrides = undefined as ChartStyleOverrides | undefined,
|
|
57
69
|
watermarkText = undefined as string | undefined,
|
|
58
70
|
onReady = undefined as ((chart: Chart) => void) | undefined,
|
|
59
71
|
chart = $bindable(null) as Chart | null,
|
|
@@ -68,8 +80,10 @@
|
|
|
68
80
|
let container: HTMLDivElement;
|
|
69
81
|
let instance: Chart | null = null;
|
|
70
82
|
const indicatorIds = new Map<string, string>();
|
|
71
|
-
|
|
72
|
-
let
|
|
83
|
+
/** The stream open now (`symbol|timeframe`), or null. */
|
|
84
|
+
let streamKey: string | null = null;
|
|
85
|
+
/** The features last applied, as text. */
|
|
86
|
+
let featuresKey: string | null = null;
|
|
73
87
|
|
|
74
88
|
onMount(() => {
|
|
75
89
|
instance = new Chart(container, {
|
|
@@ -104,10 +118,12 @@
|
|
|
104
118
|
|
|
105
119
|
if (data) {
|
|
106
120
|
instance.setData(data);
|
|
107
|
-
} else {
|
|
121
|
+
} else if (stream) {
|
|
108
122
|
const dataAdapter = adapter ?? new BinanceAdapter();
|
|
109
123
|
instance.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });
|
|
124
|
+
streamKey = `${symbol}|${timeframe}`;
|
|
110
125
|
}
|
|
126
|
+
featuresKey = JSON.stringify($state.snapshot(features) ?? null);
|
|
111
127
|
|
|
112
128
|
onReady?.(instance);
|
|
113
129
|
});
|
|
@@ -121,44 +137,55 @@
|
|
|
121
137
|
}
|
|
122
138
|
});
|
|
123
139
|
|
|
140
|
+
// A stream of its own while it has no data; `stream={false}` closes it. Data given later leaves it be.
|
|
124
141
|
$effect(() => {
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
142
|
+
const key = `${symbol}|${timeframe}`;
|
|
143
|
+
const on = stream;
|
|
144
|
+
const hasData = !!data;
|
|
145
|
+
if (!instance) return;
|
|
146
|
+
if (!on) {
|
|
147
|
+
if (streamKey !== null) instance.disconnectStream();
|
|
148
|
+
streamKey = null;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (hasData || streamKey === key) return;
|
|
152
|
+
streamKey = key;
|
|
131
153
|
instance.disconnectStream();
|
|
132
154
|
const dataAdapter = adapter ?? new BinanceAdapter();
|
|
133
|
-
instance.connect({ adapter: dataAdapter, symbol
|
|
155
|
+
instance.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });
|
|
134
156
|
if (watermarkText) instance.setWatermark(watermarkText);
|
|
135
157
|
});
|
|
136
158
|
|
|
159
|
+
$effect(() => {
|
|
160
|
+
const next = $state.snapshot(features);
|
|
161
|
+
const key = JSON.stringify(next ?? null);
|
|
162
|
+
if (!instance || key === featuresKey) return;
|
|
163
|
+
featuresKey = key;
|
|
164
|
+
if (next) instance.setFeatures(next);
|
|
165
|
+
});
|
|
166
|
+
|
|
137
167
|
$effect(() => { instance?.setTheme(resolveTheme(theme)); });
|
|
138
168
|
$effect(() => { instance?.setChartType(chartType); });
|
|
139
169
|
$effect(() => { if (data) instance?.setData(data); });
|
|
140
170
|
|
|
141
171
|
$effect(() => {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
for (const [name, instanceId] of indicatorIds) {
|
|
145
|
-
if (!desired.has(name)) {
|
|
146
|
-
instance.removeIndicator(instanceId);
|
|
147
|
-
indicatorIds.delete(name);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
for (const name of indicators) {
|
|
151
|
-
if (!indicatorIds.has(name)) {
|
|
152
|
-
const instanceId = instance.addIndicator(name);
|
|
153
|
-
if (instanceId) indicatorIds.set(name, instanceId);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
172
|
+
const specs = $state.snapshot(indicators) as IndicatorSpec[];
|
|
173
|
+
if (instance) syncIndicators(instance, specs, indicatorIds);
|
|
156
174
|
});
|
|
157
175
|
|
|
158
176
|
$effect(() => { if (signalMarkers) instance?.setSignalMarkers(signalMarkers); });
|
|
159
177
|
$effect(() => { if (signalMarkerStyle) instance?.setSignalMarkerStyle(signalMarkerStyle); });
|
|
160
178
|
$effect(() => { if (tradeZones) instance?.setTradeZones(tradeZones); });
|
|
161
179
|
$effect(() => { if (tradeZoneStyle) instance?.setTradeZoneStyle(tradeZoneStyle); });
|
|
180
|
+
// All of the host's overrides: keys left out of the prop are taken away.
|
|
181
|
+
// Without the prop, overrides set through the chart itself are left alone.
|
|
182
|
+
let overridesGiven = false;
|
|
183
|
+
$effect(() => {
|
|
184
|
+
const next = $state.snapshot(overrides);
|
|
185
|
+
if (next === undefined && !overridesGiven) return;
|
|
186
|
+
overridesGiven = next !== undefined;
|
|
187
|
+
instance?.setOverrides(next ?? {});
|
|
188
|
+
});
|
|
162
189
|
</script>
|
|
163
190
|
|
|
164
191
|
<div bind:this={container} style="width:100%;height:100%"></div>
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { Chart } from '@tradecanvas/chart';
|
|
2
|
-
import type { ChartType, TimeFrame, FeaturesConfig, Theme, OHLCBar, SignalMarker, TradeZone, SignalMarkerStyle, TradeZoneStyle, DataAdapter } from '@tradecanvas/chart';
|
|
2
|
+
import type { ChartType, TimeFrame, FeaturesConfig, Theme, OHLCBar, SignalMarker, TradeZone, SignalMarkerStyle, TradeZoneStyle, DataAdapter, ChartStyleOverrides, IndicatorSpec } from '@tradecanvas/chart';
|
|
3
3
|
interface Props {
|
|
4
4
|
symbol?: string;
|
|
5
5
|
timeframe?: TimeFrame;
|
|
6
6
|
theme?: 'dark' | 'light' | Theme;
|
|
7
7
|
chartType?: ChartType;
|
|
8
|
-
|
|
8
|
+
/** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */
|
|
9
|
+
indicators?: IndicatorSpec[];
|
|
10
|
+
/** Static bars: the chart shows these, and opens no stream of its own when it has them at mount. */
|
|
9
11
|
data?: OHLCBar[];
|
|
10
12
|
adapter?: DataAdapter;
|
|
13
|
+
/** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */
|
|
14
|
+
stream?: boolean;
|
|
11
15
|
historyLimit?: number;
|
|
16
|
+
/** What users can do on the chart; changes after mount are applied too (the keys given). */
|
|
12
17
|
features?: FeaturesConfig;
|
|
13
18
|
autoScale?: boolean;
|
|
14
19
|
signalMarkers?: SignalMarker[];
|
|
15
20
|
signalMarkerStyle?: SignalMarkerStyle;
|
|
16
21
|
tradeZones?: TradeZone[];
|
|
17
22
|
tradeZoneStyle?: TradeZoneStyle;
|
|
23
|
+
/** Style overrides, by key: all of your app's (`chart.setOverrides`). */
|
|
24
|
+
overrides?: ChartStyleOverrides;
|
|
18
25
|
watermarkText?: string;
|
|
19
26
|
onReady?: (chart: Chart) => void;
|
|
20
27
|
chart?: Chart | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradecanvas/svelte",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Svelte 5 component for @tradecanvas/chart — reactive props, runes, zero boilerplate.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"README.md"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@tradecanvas/chart": "1.
|
|
38
|
+
"@tradecanvas/chart": "1.14.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"svelte": ">=5.0.0"
|