@operato/scene-scichart 2.0.0-beta.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +19 -0
- package/README.md +13 -0
- package/assets/favicon.ico +0 -0
- package/assets/images/spinner.png +0 -0
- package/db.sqlite +0 -0
- package/dist/charts/sci-candle-stick-chart.d.ts +19 -0
- package/dist/charts/sci-candle-stick-chart.js +248 -0
- package/dist/charts/sci-candle-stick-chart.js.map +1 -0
- package/dist/charts/volume-pallette-provider.d.ts +12 -0
- package/dist/charts/volume-pallette-provider.js +21 -0
- package/dist/charts/volume-pallette-provider.js.map +1 -0
- package/dist/data/binance-rest-client.d.ts +14 -0
- package/dist/data/binance-rest-client.js +53 -0
- package/dist/data/binance-rest-client.js.map +1 -0
- package/dist/editors/index.d.ts +0 -0
- package/dist/editors/index.js +2 -0
- package/dist/editors/index.js.map +1 -0
- package/dist/groups/index.d.ts +0 -0
- package/dist/groups/index.js +2 -0
- package/dist/groups/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/scichart-candle-stick.d.ts +10 -0
- package/dist/scichart-candle-stick.js +50 -0
- package/dist/scichart-candle-stick.js.map +1 -0
- package/dist/scichart-timeseries.d.ts +23 -0
- package/dist/scichart-timeseries.js +118 -0
- package/dist/scichart-timeseries.js.map +1 -0
- package/dist/scichart.d.ts +20 -0
- package/dist/scichart.js +70 -0
- package/dist/scichart.js.map +1 -0
- package/dist/templates/index.d.ts +14 -0
- package/dist/templates/index.js +4 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/scichart-candle-stick.d.ts +14 -0
- package/dist/templates/scichart-candle-stick.js +16 -0
- package/dist/templates/scichart-candle-stick.js.map +1 -0
- package/dist/templates/scichart.d.ts +14 -0
- package/dist/templates/scichart.js +16 -0
- package/dist/templates/scichart.js.map +1 -0
- package/dist/themes/app-theme.d.ts +56 -0
- package/dist/themes/app-theme.js +35 -0
- package/dist/themes/app-theme.js.map +1 -0
- package/icons/no-image.png +0 -0
- package/icons/scichart-candle-stick.png +0 -0
- package/icons/scichart.png +0 -0
- package/logs/.08636eb59927f12972f6774f5947c8507b3564c2-audit.json +25 -0
- package/logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json +30 -0
- package/logs/application-2024-03-15-04.log +28 -0
- package/logs/application-2024-03-17-03.log +12 -0
- package/logs/application-2024-03-17-04.log +6 -0
- package/logs/connections-2024-03-15-03.log +82 -0
- package/logs/connections-2024-03-15-04.log +164 -0
- package/logs/connections-2024-03-17-03.log +88 -0
- package/logs/connections-2024-03-17-04.log +44 -0
- package/package.json +62 -0
- package/schema.graphql +3969 -0
- package/src/charts/sci-candle-stick-chart.ts +305 -0
- package/src/charts/volume-pallette-provider.ts +41 -0
- package/src/data/binance-rest-client.ts +74 -0
- package/src/editors/index.ts +0 -0
- package/src/groups/index.ts +0 -0
- package/src/index.ts +2 -0
- package/src/scichart-candle-stick.ts +60 -0
- package/src/scichart-timeseries.ts +156 -0
- package/src/scichart.ts +88 -0
- package/src/templates/index.ts +4 -0
- package/src/templates/scichart-candle-stick.ts +16 -0
- package/src/templates/scichart.ts +16 -0
- package/src/themes/app-theme.ts +72 -0
- package/things-scene.config.js +9 -0
- package/translations/en.json +3 -0
- package/translations/ja.json +3 -0
- package/translations/ko.json +3 -0
- package/translations/ms.json +3 -0
- package/translations/zh.json +3 -0
- package/tsconfig.json +22 -0
- package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,305 @@
|
|
1
|
+
import { LitElement, PropertyValues, PropertyValueMap, css, html } from 'lit'
|
2
|
+
import { customElement, property, query, state } from 'lit/decorators.js'
|
3
|
+
|
4
|
+
import {
|
5
|
+
SciChartSurface,
|
6
|
+
NumberRange,
|
7
|
+
NumericAxis,
|
8
|
+
OhlcDataSeries,
|
9
|
+
FastCandlestickRenderableSeries,
|
10
|
+
ZoomPanModifier,
|
11
|
+
ZoomExtentsModifier,
|
12
|
+
MouseWheelZoomModifier,
|
13
|
+
ENumericFormat,
|
14
|
+
DateTimeNumericAxis,
|
15
|
+
EAutoRange,
|
16
|
+
FastLineRenderableSeries,
|
17
|
+
XyMovingAverageFilter,
|
18
|
+
SciChartOverview,
|
19
|
+
CursorModifier,
|
20
|
+
CursorTooltipSvgAnnotation,
|
21
|
+
SeriesInfo,
|
22
|
+
EDataSeriesType,
|
23
|
+
ESeriesType,
|
24
|
+
IRenderableSeries,
|
25
|
+
FastMountainRenderableSeries,
|
26
|
+
GradientParams,
|
27
|
+
Point,
|
28
|
+
OhlcSeriesInfo,
|
29
|
+
FastColumnRenderableSeries,
|
30
|
+
XyDataSeries,
|
31
|
+
FastOhlcRenderableSeries
|
32
|
+
} from 'scichart'
|
33
|
+
|
34
|
+
import { appTheme } from '../themes/app-theme'
|
35
|
+
import { VolumePaletteProvider } from './volume-pallette-provider'
|
36
|
+
import { simpleBinanceRestClient } from '../data/binance-rest-client'
|
37
|
+
|
38
|
+
const Y_AXIS_VOLUME_ID = 'Y_AXIS_VOLUME_ID'
|
39
|
+
|
40
|
+
SciChartSurface.configure({
|
41
|
+
dataUrl: `/node_modules/scichart/_wasm/scichart2d.data`,
|
42
|
+
wasmUrl: `/node_modules/scichart/_wasm/scichart2d.wasm`
|
43
|
+
})
|
44
|
+
|
45
|
+
@customElement('sci-candle-stock-chart')
|
46
|
+
export class SciCandleStockChart extends LitElement {
|
47
|
+
static styles = [
|
48
|
+
css`
|
49
|
+
:host {
|
50
|
+
display: flex;
|
51
|
+
flex-direction: column;
|
52
|
+
|
53
|
+
width: 100%;
|
54
|
+
}
|
55
|
+
|
56
|
+
#chart {
|
57
|
+
flex: 8;
|
58
|
+
}
|
59
|
+
|
60
|
+
#overview {
|
61
|
+
flex: 2;
|
62
|
+
}
|
63
|
+
`
|
64
|
+
]
|
65
|
+
|
66
|
+
render() {
|
67
|
+
return html`
|
68
|
+
<div id="chart"></div>
|
69
|
+
<div id="overview"></div>
|
70
|
+
`
|
71
|
+
}
|
72
|
+
|
73
|
+
@property({ type: String, attribute: 'series-type' }) seriesType: 'candle-stick' | 'ohlc' = 'candle-stick'
|
74
|
+
|
75
|
+
@state() candlestickChartSeries!: FastCandlestickRenderableSeries
|
76
|
+
@state() ohlcChartSeries!: FastOhlcRenderableSeries
|
77
|
+
@state() sciChartSurface?: SciChartSurface
|
78
|
+
@state() sciChartOverview?: SciChartOverview
|
79
|
+
|
80
|
+
@query('#chart') chart!: HTMLDivElement
|
81
|
+
@query('#overview') overview!: HTMLDivElement
|
82
|
+
|
83
|
+
disconnectedCallback(): void {
|
84
|
+
if (this.sciChartSurface) {
|
85
|
+
this.sciChartSurface.delete()
|
86
|
+
this.sciChartOverview!.delete()
|
87
|
+
this.sciChartSurface = undefined
|
88
|
+
this.sciChartOverview = undefined
|
89
|
+
return
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
protected async firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): Promise<void> {
|
94
|
+
const { sciChartSurface, overview, candlestickSeries, ohlcSeries } = await this.build()
|
95
|
+
|
96
|
+
this.candlestickChartSeries = candlestickSeries
|
97
|
+
this.ohlcChartSeries = ohlcSeries
|
98
|
+
this.sciChartSurface = sciChartSurface
|
99
|
+
this.sciChartOverview = overview
|
100
|
+
|
101
|
+
this.candlestickChartSeries.isVisible = this.seriesType == 'candle-stick'
|
102
|
+
this.ohlcChartSeries.isVisible = this.seriesType == 'ohlc'
|
103
|
+
}
|
104
|
+
|
105
|
+
updated(changes: PropertyValues<this>) {
|
106
|
+
if (changes.has('seriesType') && this.candlestickChartSeries) {
|
107
|
+
this.candlestickChartSeries.isVisible = this.seriesType == 'candle-stick'
|
108
|
+
this.ohlcChartSeries.isVisible = this.seriesType == 'ohlc'
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
// Override the Renderableseries to display on the scichart overview
|
113
|
+
private getOverviewSeries(defaultSeries: IRenderableSeries) {
|
114
|
+
if (defaultSeries.type === ESeriesType.CandlestickSeries) {
|
115
|
+
// Swap the default candlestick series on the overview chart for a mountain series. Same data
|
116
|
+
return new FastMountainRenderableSeries(defaultSeries.parentSurface.webAssemblyContext2D, {
|
117
|
+
dataSeries: defaultSeries.dataSeries,
|
118
|
+
fillLinearGradient: new GradientParams(new Point(0, 0), new Point(0, 1), [
|
119
|
+
{ color: appTheme.VividSkyBlue + '77', offset: 0 },
|
120
|
+
{ color: 'Transparent', offset: 1 }
|
121
|
+
]),
|
122
|
+
stroke: appTheme.VividSkyBlue
|
123
|
+
})
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
// Override the standard tooltip displayed by CursorModifier
|
128
|
+
private getTooltipLegendTemplate(seriesInfos: SeriesInfo[], svgAnnotation: CursorTooltipSvgAnnotation) {
|
129
|
+
let outputSvgString = ''
|
130
|
+
|
131
|
+
// Foreach series there will be a seriesInfo supplied by SciChart. This contains info about the series under the house
|
132
|
+
seriesInfos.forEach((seriesInfo, index) => {
|
133
|
+
const y = 20 + index * 20
|
134
|
+
const textColor = seriesInfo.stroke
|
135
|
+
let legendText = seriesInfo.formattedYValue
|
136
|
+
if (seriesInfo.dataSeriesType === EDataSeriesType.Ohlc) {
|
137
|
+
const o = seriesInfo as OhlcSeriesInfo
|
138
|
+
legendText = `Open=${o.formattedOpenValue} High=${o.formattedHighValue} Low=${o.formattedLowValue} Close=${o.formattedCloseValue}`
|
139
|
+
}
|
140
|
+
outputSvgString += `<text x="8" y="${y}" font-size="13" font-family="Verdana" fill="${textColor}">
|
141
|
+
${seriesInfo.seriesName}: ${legendText}
|
142
|
+
</text>`
|
143
|
+
})
|
144
|
+
|
145
|
+
return `<svg width="100%" height="100%">
|
146
|
+
${outputSvgString}
|
147
|
+
</svg>`
|
148
|
+
}
|
149
|
+
|
150
|
+
private async build() {
|
151
|
+
// Create a SciChartSurface
|
152
|
+
const { sciChartSurface, wasmContext } = await SciChartSurface.create(this.chart, {
|
153
|
+
theme: appTheme.SciChartJsTheme
|
154
|
+
})
|
155
|
+
|
156
|
+
// Add an XAxis of type DateTimeAxis
|
157
|
+
// Note for crypto data this is fine, but for stocks/forex you will need to use CategoryAxis which collapses gaps at weekends
|
158
|
+
// In future we have a hybrid IndexDateAxis which 'magically' solves problems of different # of points in stock market datasetd with gaps
|
159
|
+
const xAxis = new DateTimeNumericAxis(wasmContext, {
|
160
|
+
// autoRange.never as we're setting visibleRange explicitly below. If you dont do this, leave this flag default
|
161
|
+
autoRange: EAutoRange.Never
|
162
|
+
})
|
163
|
+
sciChartSurface.xAxes.add(xAxis)
|
164
|
+
|
165
|
+
// Create a NumericAxis on the YAxis with 2 Decimal Places
|
166
|
+
sciChartSurface.yAxes.add(
|
167
|
+
new NumericAxis(wasmContext, {
|
168
|
+
growBy: new NumberRange(0.1, 0.1),
|
169
|
+
labelFormat: ENumericFormat.Decimal,
|
170
|
+
labelPrecision: 2,
|
171
|
+
labelPrefix: '$',
|
172
|
+
autoRange: EAutoRange.Always
|
173
|
+
})
|
174
|
+
)
|
175
|
+
|
176
|
+
// Create a secondary YAxis to host volume data on its own scale
|
177
|
+
sciChartSurface.yAxes.add(
|
178
|
+
new NumericAxis(wasmContext, {
|
179
|
+
id: Y_AXIS_VOLUME_ID,
|
180
|
+
growBy: new NumberRange(0, 4),
|
181
|
+
isVisible: false,
|
182
|
+
autoRange: EAutoRange.Always
|
183
|
+
})
|
184
|
+
)
|
185
|
+
|
186
|
+
// Fetch data from now to 300 1hr candles ago
|
187
|
+
const endDate = new Date(Date.now())
|
188
|
+
const startDate = new Date()
|
189
|
+
startDate.setHours(endDate.getHours() - 300)
|
190
|
+
const priceBars = await simpleBinanceRestClient.getCandles('BTCUSDT', '1h', startDate, endDate)
|
191
|
+
|
192
|
+
// Maps PriceBar { date, open, high, low, close, volume } to structure-of-arrays expected by scichart
|
193
|
+
const xValues: number[] = []
|
194
|
+
const openValues: number[] = []
|
195
|
+
const highValues: number[] = []
|
196
|
+
const lowValues: number[] = []
|
197
|
+
const closeValues: number[] = []
|
198
|
+
const volumeValues: number[] = []
|
199
|
+
priceBars.forEach((priceBar: any) => {
|
200
|
+
xValues.push(priceBar.date)
|
201
|
+
openValues.push(priceBar.open)
|
202
|
+
highValues.push(priceBar.high)
|
203
|
+
lowValues.push(priceBar.low)
|
204
|
+
closeValues.push(priceBar.close)
|
205
|
+
volumeValues.push(priceBar.volume)
|
206
|
+
})
|
207
|
+
|
208
|
+
// Zoom to the latest 100 candles
|
209
|
+
const startViewportRange = new Date()
|
210
|
+
startViewportRange.setHours(startDate.getHours() - 100)
|
211
|
+
xAxis.visibleRange = new NumberRange(startViewportRange.getTime() / 1000, endDate.getTime() / 1000)
|
212
|
+
|
213
|
+
// Create and add the Candlestick series
|
214
|
+
// The Candlestick Series requires a special dataseries type called OhlcDataSeries with o,h,l,c and date values
|
215
|
+
const candleDataSeries = new OhlcDataSeries(wasmContext, {
|
216
|
+
xValues,
|
217
|
+
openValues,
|
218
|
+
highValues,
|
219
|
+
lowValues,
|
220
|
+
closeValues,
|
221
|
+
dataSeriesName: 'BTC/USDT'
|
222
|
+
})
|
223
|
+
const candlestickSeries = new FastCandlestickRenderableSeries(wasmContext, {
|
224
|
+
dataSeries: candleDataSeries,
|
225
|
+
stroke: appTheme.ForegroundColor, // used by cursorModifier below
|
226
|
+
strokeThickness: 1,
|
227
|
+
brushUp: appTheme.VividGreen + '77',
|
228
|
+
brushDown: appTheme.MutedRed + '77',
|
229
|
+
strokeUp: appTheme.VividGreen,
|
230
|
+
strokeDown: appTheme.MutedRed
|
231
|
+
})
|
232
|
+
sciChartSurface.renderableSeries.add(candlestickSeries)
|
233
|
+
|
234
|
+
// Add an Ohlcseries. this will be invisible to begin with
|
235
|
+
const ohlcSeries = new FastOhlcRenderableSeries(wasmContext, {
|
236
|
+
dataSeries: candleDataSeries,
|
237
|
+
stroke: appTheme.ForegroundColor, // used by cursorModifier below
|
238
|
+
strokeThickness: 1,
|
239
|
+
dataPointWidth: 0.9,
|
240
|
+
strokeUp: appTheme.VividGreen,
|
241
|
+
strokeDown: appTheme.MutedRed,
|
242
|
+
isVisible: false
|
243
|
+
})
|
244
|
+
sciChartSurface.renderableSeries.add(ohlcSeries)
|
245
|
+
|
246
|
+
// Add some moving averages using SciChart's filters/transforms API
|
247
|
+
// when candleDataSeries updates, XyMovingAverageFilter automatically recomputes
|
248
|
+
sciChartSurface.renderableSeries.add(
|
249
|
+
new FastLineRenderableSeries(wasmContext, {
|
250
|
+
dataSeries: new XyMovingAverageFilter(candleDataSeries, {
|
251
|
+
dataSeriesName: 'Moving Average (20)',
|
252
|
+
length: 20
|
253
|
+
}),
|
254
|
+
stroke: appTheme.VividSkyBlue
|
255
|
+
})
|
256
|
+
)
|
257
|
+
|
258
|
+
sciChartSurface.renderableSeries.add(
|
259
|
+
new FastLineRenderableSeries(wasmContext, {
|
260
|
+
dataSeries: new XyMovingAverageFilter(candleDataSeries, {
|
261
|
+
dataSeriesName: 'Moving Average (50)',
|
262
|
+
length: 50
|
263
|
+
}),
|
264
|
+
stroke: appTheme.VividPink
|
265
|
+
})
|
266
|
+
)
|
267
|
+
|
268
|
+
// Add volume data onto the chart
|
269
|
+
sciChartSurface.renderableSeries.add(
|
270
|
+
new FastColumnRenderableSeries(wasmContext, {
|
271
|
+
dataSeries: new XyDataSeries(wasmContext, { xValues, yValues: volumeValues, dataSeriesName: 'Volume' }),
|
272
|
+
strokeThickness: 0,
|
273
|
+
// This is how we get volume to scale - on a hidden YAxis
|
274
|
+
yAxisId: Y_AXIS_VOLUME_ID,
|
275
|
+
// This is how we colour volume bars red or green
|
276
|
+
paletteProvider: new VolumePaletteProvider(
|
277
|
+
candleDataSeries,
|
278
|
+
appTheme.VividGreen + '77',
|
279
|
+
appTheme.MutedRed + '77'
|
280
|
+
)
|
281
|
+
})
|
282
|
+
)
|
283
|
+
|
284
|
+
// Optional: Add some interactivity modifiers
|
285
|
+
sciChartSurface.chartModifiers.add(
|
286
|
+
new ZoomExtentsModifier(),
|
287
|
+
new ZoomPanModifier(),
|
288
|
+
new MouseWheelZoomModifier(),
|
289
|
+
new CursorModifier({
|
290
|
+
crosshairStroke: appTheme.VividOrange,
|
291
|
+
axisLabelFill: appTheme.VividOrange,
|
292
|
+
tooltipLegendTemplate: this.getTooltipLegendTemplate
|
293
|
+
})
|
294
|
+
)
|
295
|
+
|
296
|
+
// Add Overview chart. This will automatically bind to the parent surface
|
297
|
+
// displaying its series. Zooming the chart will zoom the overview and vice versa
|
298
|
+
const overview = await SciChartOverview.create(sciChartSurface, this.overview, {
|
299
|
+
theme: appTheme.SciChartJsTheme,
|
300
|
+
transformRenderableSeries: this.getOverviewSeries as any
|
301
|
+
})
|
302
|
+
|
303
|
+
return { sciChartSurface, overview, candlestickSeries, ohlcSeries }
|
304
|
+
}
|
305
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import {
|
2
|
+
OhlcDataSeries,
|
3
|
+
IRenderableSeries,
|
4
|
+
EFillPaletteMode,
|
5
|
+
IFillPaletteProvider,
|
6
|
+
IPointMetadata,
|
7
|
+
parseColorToUIntArgb
|
8
|
+
} from 'scichart'
|
9
|
+
|
10
|
+
export class VolumePaletteProvider implements IFillPaletteProvider {
|
11
|
+
fillPaletteMode: EFillPaletteMode = EFillPaletteMode.SOLID
|
12
|
+
private ohlcDataSeries: OhlcDataSeries
|
13
|
+
private upColorArgb: number
|
14
|
+
private downColorArgb: number
|
15
|
+
|
16
|
+
constructor(masterData: OhlcDataSeries, upColor: string, downColor: string) {
|
17
|
+
this.upColorArgb = parseColorToUIntArgb(upColor)
|
18
|
+
this.downColorArgb = parseColorToUIntArgb(downColor)
|
19
|
+
this.ohlcDataSeries = masterData
|
20
|
+
}
|
21
|
+
onAttached(parentSeries: IRenderableSeries): void {}
|
22
|
+
onDetached(): void {}
|
23
|
+
|
24
|
+
// Return up or down color for the volume bars depending on Ohlc data
|
25
|
+
overrideFillArgb(xValue: number, yValue: number, index: number, opacity?: number, metadata?: IPointMetadata): number {
|
26
|
+
const isUpCandle =
|
27
|
+
this.ohlcDataSeries.getNativeOpenValues().get(index) >= this.ohlcDataSeries.getNativeCloseValues().get(index)
|
28
|
+
return isUpCandle ? this.upColorArgb : this.downColorArgb
|
29
|
+
}
|
30
|
+
|
31
|
+
// Override stroke as well, even though strokethickness is 0, because stroke is used if column thickness goes to 0.
|
32
|
+
overrideStrokeArgb(
|
33
|
+
xValue: number,
|
34
|
+
yValue: number,
|
35
|
+
index: number,
|
36
|
+
opacity?: number,
|
37
|
+
metadata?: IPointMetadata
|
38
|
+
): number {
|
39
|
+
return this.overrideFillArgb(xValue, yValue, index, opacity, metadata)
|
40
|
+
}
|
41
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/**
|
2
|
+
* Defines a price bar with Open, High, Low, Close and Date encoded as number
|
3
|
+
*/
|
4
|
+
export type TPriceBar = {
|
5
|
+
date: number
|
6
|
+
open: number
|
7
|
+
high: number
|
8
|
+
low: number
|
9
|
+
close: number
|
10
|
+
volume: number
|
11
|
+
}
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Parses JSON candles into TPriceBar array
|
15
|
+
* @param candles
|
16
|
+
*/
|
17
|
+
const parseCandles = (candles: any[]): TPriceBar[] => {
|
18
|
+
const priceBars: TPriceBar[] = []
|
19
|
+
|
20
|
+
candles.forEach((candle: any) => {
|
21
|
+
const [timestamp, open, high, low, close, volume] = candle
|
22
|
+
const openValue = parseFloat(open)
|
23
|
+
const highValue = parseFloat(high)
|
24
|
+
const lowValue = parseFloat(low)
|
25
|
+
const closeValue = parseFloat(close)
|
26
|
+
const volumeValue = parseFloat(volume)
|
27
|
+
|
28
|
+
priceBars.push({
|
29
|
+
date: timestamp / 1000,
|
30
|
+
open: openValue,
|
31
|
+
high: highValue,
|
32
|
+
low: lowValue,
|
33
|
+
close: closeValue,
|
34
|
+
volume: volumeValue
|
35
|
+
})
|
36
|
+
})
|
37
|
+
|
38
|
+
return priceBars
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* Fetches candles from Binance Rest API
|
43
|
+
*/
|
44
|
+
const getCandles = async (
|
45
|
+
symbol: string,
|
46
|
+
interval: string,
|
47
|
+
startTime?: Date,
|
48
|
+
endTime?: Date,
|
49
|
+
limit: number = 500
|
50
|
+
): Promise<TPriceBar[]> => {
|
51
|
+
let url = `https://api.binance.us/api/v3/klines?symbol=${symbol}&interval=${interval}`
|
52
|
+
if (startTime) {
|
53
|
+
url += `&startTime=${startTime.getTime()}`
|
54
|
+
}
|
55
|
+
if (endTime) {
|
56
|
+
url += `&endTime=${endTime.getTime()}`
|
57
|
+
}
|
58
|
+
if (limit) {
|
59
|
+
url += `&limit=${limit}`
|
60
|
+
}
|
61
|
+
try {
|
62
|
+
console.log(`SimpleBinanceClient: Fetching ${symbol} ${interval} from ${startTime} to ${endTime}`)
|
63
|
+
const response = await fetch(url)
|
64
|
+
const data = await response.json()
|
65
|
+
return parseCandles(data)
|
66
|
+
} catch (err) {
|
67
|
+
console.error(err)
|
68
|
+
return []
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
export const simpleBinanceRestClient = {
|
73
|
+
getCandles
|
74
|
+
}
|
File without changes
|
File without changes
|
package/src/index.ts
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
3
|
+
*/
|
4
|
+
|
5
|
+
const NATURE = {
|
6
|
+
mutable: false,
|
7
|
+
resizable: true,
|
8
|
+
rotatable: true,
|
9
|
+
properties: [
|
10
|
+
{
|
11
|
+
type: 'select',
|
12
|
+
label: 'series',
|
13
|
+
name: 'series',
|
14
|
+
property: {
|
15
|
+
options: ['', 'candle-stick', 'ohlc']
|
16
|
+
}
|
17
|
+
}
|
18
|
+
]
|
19
|
+
}
|
20
|
+
|
21
|
+
import './charts/sci-candle-stick-chart'
|
22
|
+
import { Component, HTMLOverlayContainer, Properties, ComponentNature, error } from '@hatiolab/things-scene'
|
23
|
+
|
24
|
+
import { SciCandleStockChart } from './charts/sci-candle-stick-chart'
|
25
|
+
|
26
|
+
export default class ScichartCandleStick extends HTMLOverlayContainer {
|
27
|
+
static get nature(): ComponentNature {
|
28
|
+
return NATURE
|
29
|
+
}
|
30
|
+
|
31
|
+
dispose() {
|
32
|
+
super.dispose()
|
33
|
+
}
|
34
|
+
|
35
|
+
/*
|
36
|
+
* 컴포넌트의 생성 또는 속성 변화 시에 호출되며,
|
37
|
+
* 그에 따른 html element의 반영이 필요한 부분을 구현한다.
|
38
|
+
*
|
39
|
+
* ThingsComponent state => HTML element properties
|
40
|
+
*/
|
41
|
+
setElementProperties(chart: SciCandleStockChart) {
|
42
|
+
const { series = 'candle-stick' } = this.state
|
43
|
+
|
44
|
+
chart.seriesType = series
|
45
|
+
}
|
46
|
+
|
47
|
+
/*
|
48
|
+
* 컴포넌트가 ready 상태가 되거나, 컴포넌트의 속성이 변화될 시 setElementProperties 뒤에 호출된다.
|
49
|
+
* 변화에 따른 기본적인 html 속성이 super.reposition()에서 진행되고, 그 밖의 작업이 필요할 때, 오버라이드 한다.
|
50
|
+
*/
|
51
|
+
reposition() {
|
52
|
+
super.reposition()
|
53
|
+
}
|
54
|
+
|
55
|
+
get tagName() {
|
56
|
+
return 'sci-candle-stock-chart'
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
Component.register('scichart-candle-stick', ScichartCandleStick)
|
@@ -0,0 +1,156 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
3
|
+
*/
|
4
|
+
|
5
|
+
const NATURE = {
|
6
|
+
mutable: false,
|
7
|
+
resizable: true,
|
8
|
+
rotatable: true,
|
9
|
+
properties: [
|
10
|
+
{
|
11
|
+
type: 'number',
|
12
|
+
label: 'sample-count',
|
13
|
+
name: 'sampleCount'
|
14
|
+
},
|
15
|
+
{
|
16
|
+
type: 'number',
|
17
|
+
label: 'max-value',
|
18
|
+
name: 'maxValue'
|
19
|
+
},
|
20
|
+
{
|
21
|
+
type: 'string',
|
22
|
+
label: 'attr-x',
|
23
|
+
name: 'attrX'
|
24
|
+
},
|
25
|
+
{
|
26
|
+
type: 'string',
|
27
|
+
label: 'attr-y',
|
28
|
+
name: 'attrY'
|
29
|
+
}
|
30
|
+
]
|
31
|
+
}
|
32
|
+
|
33
|
+
import { Component, HTMLOverlayContainer, Properties, ComponentNature, error } from '@hatiolab/things-scene'
|
34
|
+
|
35
|
+
import {
|
36
|
+
MouseWheelZoomModifier,
|
37
|
+
FastLineRenderableSeries,
|
38
|
+
XyDataSeries,
|
39
|
+
ZoomExtentsModifier,
|
40
|
+
ZoomPanModifier,
|
41
|
+
NumberRange,
|
42
|
+
EAxisAlignment,
|
43
|
+
EAutoRange
|
44
|
+
} from 'scichart'
|
45
|
+
|
46
|
+
import { SciChartSurface } from 'scichart/Charting/Visuals/SciChartSurface'
|
47
|
+
import { NumericAxis } from 'scichart/Charting/Visuals/Axis/NumericAxis'
|
48
|
+
|
49
|
+
SciChartSurface.configure({
|
50
|
+
dataUrl: `/node_modules/scichart/_wasm/scichart2d.data`,
|
51
|
+
wasmUrl: `/node_modules/scichart/_wasm/scichart2d.wasm`
|
52
|
+
})
|
53
|
+
|
54
|
+
export default class ScichartTimeSeries extends HTMLOverlayContainer {
|
55
|
+
static get nature() {
|
56
|
+
return NATURE
|
57
|
+
}
|
58
|
+
|
59
|
+
_anchor?: HTMLDivElement
|
60
|
+
|
61
|
+
async oncreate_element(div: HTMLDivElement) {
|
62
|
+
const { sciChartSurface, wasmContext } = await SciChartSurface.create(div)
|
63
|
+
var { sampleCount, maxValue } = this.state
|
64
|
+
|
65
|
+
// SciChartSurface.setRuntimeLicenseKey('YOUR_RUNTIME_KEY')
|
66
|
+
|
67
|
+
const xAxis = new NumericAxis(wasmContext, {
|
68
|
+
axisTitle: 'X Axis',
|
69
|
+
autoRange: EAutoRange.Never,
|
70
|
+
axisAlignment: EAxisAlignment.Bottom,
|
71
|
+
visibleRange: new NumberRange(0, sampleCount)
|
72
|
+
})
|
73
|
+
const yAxis = new NumericAxis(wasmContext, {
|
74
|
+
axisTitle: 'Y Axis',
|
75
|
+
autoRange: EAutoRange.Never,
|
76
|
+
visibleRange: new NumberRange(0, maxValue)
|
77
|
+
})
|
78
|
+
|
79
|
+
sciChartSurface.xAxes.add(xAxis)
|
80
|
+
sciChartSurface.yAxes.add(yAxis)
|
81
|
+
|
82
|
+
const dataSeries = new XyDataSeries(wasmContext, {
|
83
|
+
xValues: this.dataSet.map(d => d.xValue),
|
84
|
+
yValues: this.dataSet.map(d => d.yValue)
|
85
|
+
})
|
86
|
+
|
87
|
+
const lineSeries = new FastLineRenderableSeries(wasmContext, {
|
88
|
+
dataSeries: dataSeries,
|
89
|
+
xAxisId: sciChartSurface.xAxes.get(0).id,
|
90
|
+
yAxisId: sciChartSurface.yAxes.get(0).id,
|
91
|
+
stroke: '#FF6600',
|
92
|
+
strokeThickness: 2
|
93
|
+
})
|
94
|
+
|
95
|
+
sciChartSurface.renderableSeries.add(lineSeries)
|
96
|
+
|
97
|
+
// ZoomPanModifier, MouseWheelZoomModifier, ZoomExtentsModifier 추가
|
98
|
+
// ZoomPanModifier: Chart를 드래그하여 이동
|
99
|
+
// MouseWheelZoomModifier: 마우스 휠로 Chart Zoom
|
100
|
+
// ZoomExtentsModifier: Chart의 전체 범위로 Zoom
|
101
|
+
sciChartSurface.chartModifiers.add(
|
102
|
+
new ZoomPanModifier({ enableZoom: true }),
|
103
|
+
new MouseWheelZoomModifier(),
|
104
|
+
new ZoomExtentsModifier()
|
105
|
+
)
|
106
|
+
}
|
107
|
+
|
108
|
+
dispose() {
|
109
|
+
super.dispose()
|
110
|
+
|
111
|
+
delete this._anchor
|
112
|
+
}
|
113
|
+
|
114
|
+
/*
|
115
|
+
* 컴포넌트의 생성 또는 속성 변화 시에 호출되며,
|
116
|
+
* 그에 따른 html element의 반영이 필요한 부분을 구현한다.
|
117
|
+
*
|
118
|
+
* ThingsComponent state => HTML element properties
|
119
|
+
*/
|
120
|
+
setElementProperties(div: HTMLDivElement) {}
|
121
|
+
|
122
|
+
/*
|
123
|
+
* 컴포넌트가 ready 상태가 되거나, 컴포넌트의 속성이 변화될 시 setElementProperties 뒤에 호출된다.
|
124
|
+
* 변화에 따른 기본적인 html 속성이 super.reposition()에서 진행되고, 그 밖의 작업이 필요할 때, 오버라이드 한다.
|
125
|
+
*/
|
126
|
+
reposition() {
|
127
|
+
super.reposition()
|
128
|
+
}
|
129
|
+
|
130
|
+
get dataSet(): { xValue: number; yValue: number }[] {
|
131
|
+
var { attrX, attrY, data } = this.state
|
132
|
+
|
133
|
+
if (!(data instanceof Array)) {
|
134
|
+
return []
|
135
|
+
}
|
136
|
+
|
137
|
+
return data
|
138
|
+
.map(item => {
|
139
|
+
if (!item || typeof item !== 'object') {
|
140
|
+
return
|
141
|
+
}
|
142
|
+
|
143
|
+
return {
|
144
|
+
xValue: item[attrX],
|
145
|
+
yValue: item[attrY]
|
146
|
+
}
|
147
|
+
})
|
148
|
+
.filter(Boolean) as { xValue: number; yValue: number }[]
|
149
|
+
}
|
150
|
+
|
151
|
+
get tagName() {
|
152
|
+
return 'div'
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
Component.register('scichart-timeseries', ScichartTimeSeries)
|