binbot-charts 0.12.12 → 0.12.14
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 +5 -5
- package/dist/main.cjs +78 -90
- package/dist/main.cjs.map +1 -1
- package/dist/main.js +79 -91
- package/dist/main.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -3,26 +3,26 @@ Import it in your project as a React component
|
|
|
3
3
|
|
|
4
4
|
`import TVChartContainer from 'binbot-charts'`
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
## Multi-Exchange Support
|
|
8
7
|
|
|
9
8
|
This library now supports multiple cryptocurrency exchanges. You can configure which exchange to use and which exchanges to make available for symbol search.
|
|
10
9
|
|
|
11
10
|
### Supported Exchanges
|
|
11
|
+
|
|
12
12
|
- **Binance** - Default exchange
|
|
13
13
|
- **KuCoin** - Added in v0.7.3+
|
|
14
14
|
|
|
15
15
|
### Usage Example
|
|
16
16
|
|
|
17
17
|
```jsx
|
|
18
|
-
import TVChartContainer, { SUPPORTED_EXCHANGES } from
|
|
18
|
+
import TVChartContainer, { SUPPORTED_EXCHANGES } from "binbot-charts";
|
|
19
19
|
|
|
20
20
|
function MyChart() {
|
|
21
21
|
return (
|
|
22
22
|
<TVChartContainer
|
|
23
23
|
symbol="BTCUSDT"
|
|
24
24
|
interval="1h"
|
|
25
|
-
exchange="binance"
|
|
25
|
+
exchange="binance" // or "kucoin"
|
|
26
26
|
supportedExchanges={["binance", "kucoin"]}
|
|
27
27
|
/>
|
|
28
28
|
);
|
|
@@ -45,14 +45,13 @@ function MyChart() {
|
|
|
45
45
|
You can also import and use the exchange configurations directly:
|
|
46
46
|
|
|
47
47
|
```jsx
|
|
48
|
-
import { SUPPORTED_EXCHANGES, ExchangeConfig } from
|
|
48
|
+
import { SUPPORTED_EXCHANGES, ExchangeConfig } from "binbot-charts";
|
|
49
49
|
|
|
50
50
|
// Access exchange configuration
|
|
51
51
|
const binanceConfig = SUPPORTED_EXCHANGES.binance;
|
|
52
52
|
console.log(binanceConfig.restApiUrl); // "https://api.binance.com"
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
|
|
56
55
|
## How to start
|
|
57
56
|
|
|
58
57
|
1. Run `npm install && npm start`. It will build the project and open a default browser with the Charting Library.
|
|
@@ -64,4 +63,5 @@ console.log(binanceConfig.restApiUrl); // "https://api.binance.com"
|
|
|
64
63
|
This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
|
|
65
64
|
|
|
66
65
|
## Notes
|
|
66
|
+
|
|
67
67
|
The earliest supported version of Node of the charting library for these examples is `v20`.
|
package/dist/main.cjs
CHANGED
|
@@ -384,7 +384,10 @@ function getAllSymbols(symbol, apiHost = "https://api.binance.com", exchange = "
|
|
|
384
384
|
return __async(this, null, function* () {
|
|
385
385
|
let newSymbols = [];
|
|
386
386
|
try {
|
|
387
|
-
const data = yield makeApiRequest(
|
|
387
|
+
const data = yield makeApiRequest(
|
|
388
|
+
`api/v3/exchangeInfo?symbol=${symbol.toUpperCase()}`,
|
|
389
|
+
apiHost
|
|
390
|
+
);
|
|
388
391
|
data.symbols.forEach((item) => {
|
|
389
392
|
if (item.status === "TRADING") {
|
|
390
393
|
newSymbols.push({
|
|
@@ -477,6 +480,7 @@ var binanceAdapter = {
|
|
|
477
480
|
});
|
|
478
481
|
}
|
|
479
482
|
};
|
|
483
|
+
var kucoinFuturesBarsAbort = null;
|
|
480
484
|
var kucoinAdapter = {
|
|
481
485
|
fetchSymbolMeta(symbol, apiHost) {
|
|
482
486
|
return __async(this, null, function* () {
|
|
@@ -511,35 +515,50 @@ var kucoinAdapter = {
|
|
|
511
515
|
fetchBars(_0, _1) {
|
|
512
516
|
return __async(this, arguments, function* ({ symbol, interval, from, to }, apiHost) {
|
|
513
517
|
if (isKucoinFutures(symbol)) {
|
|
518
|
+
if (kucoinFuturesBarsAbort) {
|
|
519
|
+
kucoinFuturesBarsAbort.abort();
|
|
520
|
+
}
|
|
521
|
+
kucoinFuturesBarsAbort = new AbortController();
|
|
522
|
+
const { signal } = kucoinFuturesBarsAbort;
|
|
514
523
|
const granularity = mapKuCoinFuturesGranularity(interval);
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
524
|
+
const fromMs = from * 1e3;
|
|
525
|
+
let currentTo = to * 1e3;
|
|
526
|
+
let allCandles = [];
|
|
527
|
+
const MAX_PAGES = 10;
|
|
528
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
529
|
+
const params2 = new URLSearchParams({
|
|
530
|
+
symbol,
|
|
531
|
+
granularity: String(granularity),
|
|
532
|
+
to: String(currentTo)
|
|
533
|
+
});
|
|
534
|
+
const resp2 = yield makeApiRequest(
|
|
535
|
+
`api/v1/kline/query?${params2.toString()}`,
|
|
536
|
+
KUCOIN_FUTURES_API,
|
|
537
|
+
{ signal }
|
|
538
|
+
);
|
|
539
|
+
const raw2 = Array.isArray(resp2 == null ? void 0 : resp2.data) ? resp2.data : [];
|
|
540
|
+
if (raw2.length === 0) break;
|
|
541
|
+
const candles2 = raw2.map((bar) => [
|
|
542
|
+
Number(bar[0]),
|
|
543
|
+
Number(bar[1]),
|
|
544
|
+
Number(bar[2]),
|
|
545
|
+
Number(bar[3]),
|
|
546
|
+
Number(bar[4]),
|
|
547
|
+
Number(bar[5])
|
|
548
|
+
]);
|
|
549
|
+
allCandles = allCandles.concat(candles2);
|
|
550
|
+
const earliest = Math.min(...candles2.map((c) => c[0]));
|
|
551
|
+
if (earliest <= fromMs) break;
|
|
552
|
+
currentTo = earliest;
|
|
553
|
+
}
|
|
554
|
+
const seen = /* @__PURE__ */ new Set();
|
|
555
|
+
const unique = allCandles.filter((c) => {
|
|
556
|
+
if (seen.has(c[0])) return false;
|
|
557
|
+
seen.add(c[0]);
|
|
558
|
+
return true;
|
|
521
559
|
});
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
KUCOIN_FUTURES_API
|
|
525
|
-
);
|
|
526
|
-
const raw2 = Array.isArray(resp2 == null ? void 0 : resp2.data) ? resp2.data : [];
|
|
527
|
-
const candles2 = raw2.map((bar) => [
|
|
528
|
-
Number(bar[0]),
|
|
529
|
-
// time already in ms
|
|
530
|
-
Number(bar[1]),
|
|
531
|
-
// open
|
|
532
|
-
Number(bar[2]),
|
|
533
|
-
// high
|
|
534
|
-
Number(bar[3]),
|
|
535
|
-
// low
|
|
536
|
-
Number(bar[4]),
|
|
537
|
-
// close
|
|
538
|
-
Number(bar[5])
|
|
539
|
-
// volume
|
|
540
|
-
]);
|
|
541
|
-
candles2.sort((a, b) => a[0] - b[0]);
|
|
542
|
-
return candles2;
|
|
560
|
+
unique.sort((a, b) => a[0] - b[0]);
|
|
561
|
+
return unique;
|
|
543
562
|
}
|
|
544
563
|
const type = mapKuCoinInterval(interval);
|
|
545
564
|
const params = new URLSearchParams({
|
|
@@ -608,18 +627,18 @@ var SUPPORTED_EXCHANGES = {
|
|
|
608
627
|
const isFutures = symbol == null ? void 0 : symbol.endsWith("M");
|
|
609
628
|
const apiBase = isFutures ? "https://api-futures.kucoin.com" : "https://api.kucoin.com";
|
|
610
629
|
try {
|
|
611
|
-
const data = yield makeApiRequest(
|
|
612
|
-
"
|
|
613
|
-
|
|
614
|
-
{ method: "POST" }
|
|
615
|
-
);
|
|
630
|
+
const data = yield makeApiRequest("api/v1/bullet-public", apiBase, {
|
|
631
|
+
method: "POST"
|
|
632
|
+
});
|
|
616
633
|
if (data.code === "200000" && ((_b = (_a = data.data) == null ? void 0 : _a.instanceServers) == null ? void 0 : _b.length) > 0) {
|
|
617
634
|
const server = data.data.instanceServers[0];
|
|
618
635
|
return `${server.endpoint}?token=${data.data.token}`;
|
|
619
636
|
}
|
|
620
637
|
throw new Error("Failed to get KuCoin WebSocket URL: Invalid response");
|
|
621
638
|
} catch (error) {
|
|
622
|
-
throw new Error(
|
|
639
|
+
throw new Error(
|
|
640
|
+
`Failed to get KuCoin WebSocket URL: ${(error == null ? void 0 : error.message) || String(error)}`
|
|
641
|
+
);
|
|
623
642
|
}
|
|
624
643
|
})
|
|
625
644
|
}
|
|
@@ -871,7 +890,9 @@ var Datafeed = class {
|
|
|
871
890
|
constructor(timescaleMarks = [], interval = "1h", exchangeConfig, supportedExchanges = []) {
|
|
872
891
|
this.configurationData = null;
|
|
873
892
|
this.onReady = (callback) => __async(this, null, function* () {
|
|
874
|
-
this.configurationData = yield getConfigurationData(
|
|
893
|
+
this.configurationData = yield getConfigurationData(
|
|
894
|
+
this.supportedExchanges
|
|
895
|
+
);
|
|
875
896
|
callback(this.configurationData);
|
|
876
897
|
});
|
|
877
898
|
this.searchSymbols = (userInput, exchange, symbolType, onResultReadyCallback) => __async(this, null, function* () {
|
|
@@ -889,7 +910,10 @@ var Datafeed = class {
|
|
|
889
910
|
}
|
|
890
911
|
const symbolInfo = () => __async(this, null, function* () {
|
|
891
912
|
var _a;
|
|
892
|
-
const meta = yield this.adapter.fetchSymbolMeta(
|
|
913
|
+
const meta = yield this.adapter.fetchSymbolMeta(
|
|
914
|
+
symbolName,
|
|
915
|
+
this.exchangeConfig.restApiUrl
|
|
916
|
+
);
|
|
893
917
|
const priceScale = (_a = meta.priceScale) != null ? _a : 8;
|
|
894
918
|
return {
|
|
895
919
|
name: symbolName,
|
|
@@ -917,6 +941,10 @@ var Datafeed = class {
|
|
|
917
941
|
});
|
|
918
942
|
this.getBars = (symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) => __async(this, null, function* () {
|
|
919
943
|
const { from, to, firstDataRequest } = periodParams;
|
|
944
|
+
if (!firstDataRequest) {
|
|
945
|
+
onHistoryCallback([], { noData: true });
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
920
948
|
let interval = "60";
|
|
921
949
|
if (!/[a-zA-Z]$/.test(resolution)) {
|
|
922
950
|
if (parseInt(resolution) >= 60) {
|
|
@@ -952,7 +980,7 @@ var Datafeed = class {
|
|
|
952
980
|
];
|
|
953
981
|
}
|
|
954
982
|
});
|
|
955
|
-
onHistoryCallback(bars, { noData:
|
|
983
|
+
onHistoryCallback(bars, { noData: bars.length === 0 });
|
|
956
984
|
} catch (error) {
|
|
957
985
|
console.log("[getBars]: Get error", error);
|
|
958
986
|
onErrorCallback(error);
|
|
@@ -1000,7 +1028,9 @@ var Datafeed = class {
|
|
|
1000
1028
|
}
|
|
1001
1029
|
getServerTime(onServertimeCallback) {
|
|
1002
1030
|
return __async(this, null, function* () {
|
|
1003
|
-
const serverTime = yield this.adapter.fetchServerTime(
|
|
1031
|
+
const serverTime = yield this.adapter.fetchServerTime(
|
|
1032
|
+
this.exchangeConfig.restApiUrl
|
|
1033
|
+
);
|
|
1004
1034
|
onServertimeCallback(serverTime);
|
|
1005
1035
|
});
|
|
1006
1036
|
}
|
|
@@ -1023,74 +1053,32 @@ var TVChartContainer = ({
|
|
|
1023
1053
|
const containerRef = (0, import_react2.useRef)(null);
|
|
1024
1054
|
const [chartOrderLines, setChartOrderLines] = (0, import_use_immer.useImmer)([]);
|
|
1025
1055
|
const [widgetState, setWidgetState] = (0, import_use_immer.useImmer)(null);
|
|
1026
|
-
const [symbolState, setSymbolState] = (0, import_react2.useState)(symbol);
|
|
1027
|
-
const [transformedSymbol, setTransformedSymbol] = (0, import_react2.useState)(null);
|
|
1028
|
-
const [isLoadingSymbol, setIsLoadingSymbol] = (0, import_react2.useState)(false);
|
|
1029
1056
|
const prevTimescaleMarks = (0, import_react2.useRef)(timescaleMarks);
|
|
1030
1057
|
const prevExchange = (0, import_react2.useRef)(exchange);
|
|
1058
|
+
const prevSymbol = (0, import_react2.useRef)(symbol);
|
|
1031
1059
|
(0, import_react2.useEffect)(() => {
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
const response = yield fetch(`https://api.terminal.binbot.in/symbol/${cleanSymbol}`);
|
|
1039
|
-
if (!response.ok) {
|
|
1040
|
-
console.warn(`Failed to fetch symbol metadata for ${cleanSymbol}, using original symbol`);
|
|
1041
|
-
setTransformedSymbol(symbol);
|
|
1042
|
-
return;
|
|
1043
|
-
}
|
|
1044
|
-
const result = yield response.json();
|
|
1045
|
-
if (((_a = result.data) == null ? void 0 : _a.base_asset) && ((_b = result.data) == null ? void 0 : _b.quote_asset)) {
|
|
1046
|
-
const { base_asset, quote_asset } = result.data;
|
|
1047
|
-
const formatted = exchange.toLowerCase() === "kucoin" ? `${base_asset}-${quote_asset}` : `${base_asset}${quote_asset}`;
|
|
1048
|
-
setTransformedSymbol(formatted);
|
|
1049
|
-
} else {
|
|
1050
|
-
console.warn("Invalid symbol metadata response, using original symbol");
|
|
1051
|
-
setTransformedSymbol(symbol);
|
|
1052
|
-
}
|
|
1053
|
-
} catch (error) {
|
|
1054
|
-
console.error("Error fetching symbol metadata:", error);
|
|
1055
|
-
setTransformedSymbol(symbol);
|
|
1056
|
-
} finally {
|
|
1057
|
-
setIsLoadingSymbol(false);
|
|
1058
|
-
}
|
|
1059
|
-
});
|
|
1060
|
-
fetchSymbolMetadata();
|
|
1061
|
-
}, [symbol, exchange]);
|
|
1062
|
-
(0, import_react2.useEffect)(() => {
|
|
1063
|
-
if (isLoadingSymbol || !transformedSymbol) {
|
|
1060
|
+
if (!symbol) return;
|
|
1061
|
+
if (widgetState && (symbol !== prevSymbol.current || exchange !== prevExchange.current)) {
|
|
1062
|
+
widgetState.remove();
|
|
1063
|
+
setWidgetState(null);
|
|
1064
|
+
prevSymbol.current = symbol;
|
|
1065
|
+
prevExchange.current = exchange;
|
|
1064
1066
|
return;
|
|
1065
1067
|
}
|
|
1066
1068
|
if (!widgetState) {
|
|
1067
1069
|
initializeChart(interval);
|
|
1068
|
-
|
|
1069
|
-
setSymbolState(transformedSymbol);
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
if (widgetState && exchange !== prevExchange.current) {
|
|
1073
|
-
widgetState.remove();
|
|
1074
|
-
setWidgetState(null);
|
|
1070
|
+
prevSymbol.current = symbol;
|
|
1075
1071
|
prevExchange.current = exchange;
|
|
1076
1072
|
return;
|
|
1077
1073
|
}
|
|
1078
1074
|
if (orderLines && orderLines.length > 0) {
|
|
1079
1075
|
updateOrderLines(orderLines);
|
|
1080
1076
|
}
|
|
1081
|
-
if (widgetState && transformedSymbol !== symbolState) {
|
|
1082
|
-
try {
|
|
1083
|
-
widgetState.setSymbol(transformedSymbol, interval);
|
|
1084
|
-
setSymbolState(transformedSymbol);
|
|
1085
|
-
} catch (error) {
|
|
1086
|
-
console.error("Failed to set symbol:", error);
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
1077
|
if (widgetState && prevTimescaleMarks.current && timescaleMarks !== prevTimescaleMarks.current) {
|
|
1090
1078
|
widgetState._options.datafeed.timescaleMarks = timescaleMarks;
|
|
1091
1079
|
prevTimescaleMarks.current = timescaleMarks;
|
|
1092
1080
|
}
|
|
1093
|
-
}, [orderLines, timescaleMarks, exchange,
|
|
1081
|
+
}, [symbol, orderLines, timescaleMarks, exchange, widgetState, interval]);
|
|
1094
1082
|
const initializeChart = (interval2) => {
|
|
1095
1083
|
const exchangeConfig = SUPPORTED_EXCHANGES[exchange.toLowerCase()];
|
|
1096
1084
|
if (!exchangeConfig) {
|
|
@@ -1099,7 +1087,7 @@ var TVChartContainer = ({
|
|
|
1099
1087
|
}
|
|
1100
1088
|
const supportedExchangeConfigs = supportedExchanges.map((ex) => SUPPORTED_EXCHANGES[ex.toLowerCase()]).filter(Boolean);
|
|
1101
1089
|
const widgetOptions = {
|
|
1102
|
-
symbol
|
|
1090
|
+
symbol,
|
|
1103
1091
|
datafeed: new Datafeed(
|
|
1104
1092
|
timescaleMarks,
|
|
1105
1093
|
interval2,
|