binbot-charts 0.3.1 → 0.3.2
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.
|
@@ -4,23 +4,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = TVChartContainer;
|
|
7
|
-
|
|
8
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
-
|
|
10
8
|
var _charting_library = require("../charting_library");
|
|
11
|
-
|
|
12
9
|
var _datafeed = _interopRequireDefault(require("./datafeed"));
|
|
13
|
-
|
|
14
10
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
15
|
-
|
|
16
11
|
var _useImmer = require("use-immer");
|
|
17
|
-
|
|
18
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
-
|
|
20
13
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
21
|
-
|
|
22
14
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
23
|
-
|
|
24
15
|
function TVChartContainer(_ref) {
|
|
25
16
|
let {
|
|
26
17
|
symbol = "BTCUSDT",
|
|
@@ -41,21 +32,17 @@ function TVChartContainer(_ref) {
|
|
|
41
32
|
if (!widgetState) {
|
|
42
33
|
initializeChart("1h");
|
|
43
34
|
}
|
|
44
|
-
|
|
45
35
|
if (orderLines && orderLines.length > 0) {
|
|
46
36
|
updateOrderLines(orderLines);
|
|
47
37
|
}
|
|
48
|
-
|
|
49
38
|
if (widgetState && symbol !== symbolState) {
|
|
50
39
|
widgetState.setSymbol(symbol, interval);
|
|
51
40
|
}
|
|
52
|
-
|
|
53
41
|
if (widgetState && prevTimescaleMarks.current && timescaleMarks !== prevTimescaleMarks.current) {
|
|
54
42
|
widgetState._options.datafeed.timescaleMarks = timescaleMarks;
|
|
55
43
|
prevTimescaleMarks.current = timescaleMarks;
|
|
56
44
|
}
|
|
57
45
|
}, [orderLines, timescaleMarks]);
|
|
58
|
-
|
|
59
46
|
const initializeChart = interval => {
|
|
60
47
|
const widgetOptions = {
|
|
61
48
|
symbol: symbol,
|
|
@@ -76,8 +63,9 @@ function TVChartContainer(_ref) {
|
|
|
76
63
|
const tvWidget = new _charting_library.widget(widgetOptions);
|
|
77
64
|
tvWidget.onChartReady(() => {
|
|
78
65
|
tvWidget.subscribe("onTick", event => onTick(event));
|
|
79
|
-
setWidgetState(tvWidget);
|
|
66
|
+
setWidgetState(tvWidget);
|
|
80
67
|
|
|
68
|
+
// get latest bar for last price
|
|
81
69
|
const prices = async () => {
|
|
82
70
|
const data = await tvWidget.activeChart().exportData({
|
|
83
71
|
includeTime: false,
|
|
@@ -86,11 +74,9 @@ function TVChartContainer(_ref) {
|
|
|
86
74
|
});
|
|
87
75
|
getLatestBar(data.data[data.data.length - 1]);
|
|
88
76
|
};
|
|
89
|
-
|
|
90
77
|
prices();
|
|
91
78
|
});
|
|
92
79
|
};
|
|
93
|
-
|
|
94
80
|
const updateOrderLines = orderLines => {
|
|
95
81
|
if (chartOrderLines && chartOrderLines.length > 0) {
|
|
96
82
|
chartOrderLines.forEach(item => {
|
|
@@ -104,8 +90,9 @@ function TVChartContainer(_ref) {
|
|
|
104
90
|
if (widgetState && orderLines && orderLines.length > 0) {
|
|
105
91
|
orderLines.forEach(order => {
|
|
106
92
|
const lineStyle = order.lineStyle || 0;
|
|
107
|
-
let chartOrderLine = widgetState.chart().createOrderLine().setText(order.text).setTooltip(order.tooltip).setQuantity(order.quantity).setQuantityFont("inherit 14px Arial").setQuantityBackgroundColor(order.color).setQuantityBorderColor(order.color).setLineStyle(lineStyle).setLineLength(25).setLineColor(order.color).setBodyFont("inherit 14px Arial").setBodyBorderColor(order.color).setBodyTextColor(order.color).setPrice(order.price);
|
|
93
|
+
let chartOrderLine = widgetState.chart().createOrderLine().setText(order.text).setTooltip(order.tooltip).setQuantity(order.quantity).setQuantityFont("inherit 14px Arial").setQuantityBackgroundColor(order.color).setQuantityBorderColor(order.color).setLineStyle(lineStyle).setLineLength(25).setLineColor(order.color).setBodyFont("inherit 14px Arial").setBodyBorderColor(order.color).setBodyTextColor(order.color).setPrice(order.price);
|
|
108
94
|
|
|
95
|
+
// set custom id easier search
|
|
109
96
|
chartOrderLine.id = order.id;
|
|
110
97
|
setChartOrderLines(draft => {
|
|
111
98
|
draft.push(chartOrderLine);
|
|
@@ -115,7 +102,6 @@ function TVChartContainer(_ref) {
|
|
|
115
102
|
}
|
|
116
103
|
}
|
|
117
104
|
};
|
|
118
|
-
|
|
119
105
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
120
106
|
ref: containerRef,
|
|
121
107
|
style: {
|
|
@@ -123,7 +109,6 @@ function TVChartContainer(_ref) {
|
|
|
123
109
|
}
|
|
124
110
|
});
|
|
125
111
|
}
|
|
126
|
-
|
|
127
112
|
TVChartContainer.propTypes = {
|
|
128
113
|
apiKey: _propTypes.default.string,
|
|
129
114
|
symbol: _propTypes.default.string,
|
|
@@ -4,15 +4,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _helpers = require("./helpers.js");
|
|
9
|
-
|
|
10
8
|
var _streaming = require("./streaming.js");
|
|
11
|
-
|
|
12
|
-
function
|
|
13
|
-
|
|
9
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
10
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
11
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
14
12
|
const binanceResolutions = ["1s", "1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "12h", "1d", "3d", "1w", "1M"];
|
|
15
|
-
|
|
16
13
|
const getConfigurationData = async () => {
|
|
17
14
|
return {
|
|
18
15
|
supports_marks: true,
|
|
@@ -31,34 +28,28 @@ const getConfigurationData = async () => {
|
|
|
31
28
|
}]
|
|
32
29
|
};
|
|
33
30
|
};
|
|
31
|
+
|
|
34
32
|
/**
|
|
35
33
|
* @param timescale { Array }. timescaleMark objects
|
|
36
34
|
* @param interval { string }. Klines timescale from the list of Binance Enums
|
|
37
35
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
36
|
class Datafeed {
|
|
41
37
|
constructor() {
|
|
42
38
|
let timescaleMarks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
43
|
-
|
|
44
39
|
let _interval = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "1h";
|
|
45
|
-
|
|
46
40
|
_defineProperty(this, "onReady", async callback => {
|
|
47
41
|
this.configurationData = await getConfigurationData();
|
|
48
42
|
callback(this.configurationData);
|
|
49
43
|
});
|
|
50
|
-
|
|
51
44
|
_defineProperty(this, "searchSymbols", async (userInput, exchange, symbolType, onResultReadyCallback) => {
|
|
52
45
|
const symbols = await (0, _helpers.getAllSymbols)(userInput);
|
|
53
46
|
onResultReadyCallback(symbols);
|
|
54
47
|
});
|
|
55
|
-
|
|
56
48
|
_defineProperty(this, "resolveSymbol", async (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
|
|
57
49
|
if (!symbolName) {
|
|
58
50
|
await onResolveErrorCallback("cannot resolve symbol");
|
|
59
51
|
return;
|
|
60
52
|
}
|
|
61
|
-
|
|
62
53
|
const symbolInfo = () => {
|
|
63
54
|
return {
|
|
64
55
|
ticker: symbolName,
|
|
@@ -82,11 +73,9 @@ class Datafeed {
|
|
|
82
73
|
resolution: "1h"
|
|
83
74
|
};
|
|
84
75
|
};
|
|
85
|
-
|
|
86
76
|
const symbol = await symbolInfo();
|
|
87
77
|
onSymbolResolvedCallback(symbol);
|
|
88
78
|
});
|
|
89
|
-
|
|
90
79
|
_defineProperty(this, "getBars", async (symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) => {
|
|
91
80
|
const {
|
|
92
81
|
from,
|
|
@@ -95,7 +84,6 @@ class Datafeed {
|
|
|
95
84
|
} = periodParams;
|
|
96
85
|
let interval = "60"; // 1 hour
|
|
97
86
|
// Calculate interval using resolution data
|
|
98
|
-
|
|
99
87
|
if (!/[a-zA-Z]$/.test(resolution)) {
|
|
100
88
|
if (parseInt(resolution) >= 60) {
|
|
101
89
|
interval = parseInt(resolution) / 60 + "h";
|
|
@@ -105,7 +93,6 @@ class Datafeed {
|
|
|
105
93
|
} else {
|
|
106
94
|
interval = resolution.toLowerCase().replace(/[a-z]\b/g, c => c.toLowerCase());
|
|
107
95
|
}
|
|
108
|
-
|
|
109
96
|
let urlParameters = {
|
|
110
97
|
symbol: symbolInfo.name,
|
|
111
98
|
interval: interval,
|
|
@@ -114,10 +101,8 @@ class Datafeed {
|
|
|
114
101
|
limit: 600
|
|
115
102
|
};
|
|
116
103
|
const query = Object.keys(urlParameters).map(name => `${name}=${encodeURIComponent(urlParameters[name])}`).join("&");
|
|
117
|
-
|
|
118
104
|
try {
|
|
119
105
|
const data = await (0, _helpers.makeApiRequest)(`api/v3/uiKlines?${query}`);
|
|
120
|
-
|
|
121
106
|
if (data.Response && data.Response === "Error" || data.length === 0) {
|
|
122
107
|
// "noData" should be set if there is no data in the requested period.
|
|
123
108
|
onHistoryCallback([], {
|
|
@@ -125,7 +110,6 @@ class Datafeed {
|
|
|
125
110
|
});
|
|
126
111
|
return;
|
|
127
112
|
}
|
|
128
|
-
|
|
129
113
|
let bars = [];
|
|
130
114
|
data.forEach(bar => {
|
|
131
115
|
if (bar[0] >= from * 1000 && bar[0] < to * 1000) {
|
|
@@ -147,33 +131,26 @@ class Datafeed {
|
|
|
147
131
|
onErrorCallback(error);
|
|
148
132
|
}
|
|
149
133
|
});
|
|
150
|
-
|
|
151
134
|
_defineProperty(this, "subscribeBars", (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {
|
|
152
135
|
(0, _streaming.subscribeOnStream)(symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback, this.interval);
|
|
153
136
|
});
|
|
154
|
-
|
|
155
137
|
_defineProperty(this, "unsubscribeBars", subscriberUID => {
|
|
156
138
|
(0, _streaming.unsubscribeFromStream)(subscriberUID);
|
|
157
139
|
});
|
|
158
|
-
|
|
159
140
|
this.streaming = null;
|
|
160
141
|
this.timescaleMarks = timescaleMarks;
|
|
161
142
|
this.interval = _interval;
|
|
162
143
|
}
|
|
163
|
-
|
|
164
144
|
getTimescaleMarks(symbolInfo, from, to, onDataCallback, resolution) {
|
|
165
145
|
if (this.timescaleMarks.length > 0) {
|
|
166
146
|
let timescaleMarks = Object.assign([], this.timescaleMarks);
|
|
167
147
|
onDataCallback(timescaleMarks);
|
|
168
148
|
}
|
|
169
149
|
}
|
|
170
|
-
|
|
171
150
|
async getServerTime(onServertimeCallback) {
|
|
172
151
|
const data = await (0, _helpers.makeApiRequest)(`api/v3/time`);
|
|
173
152
|
const serverTime = data.serverTime / 1000;
|
|
174
153
|
onServertimeCallback(serverTime);
|
|
175
154
|
}
|
|
176
|
-
|
|
177
155
|
}
|
|
178
|
-
|
|
179
156
|
exports.default = Datafeed;
|
|
@@ -6,9 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.getAllSymbols = getAllSymbols;
|
|
7
7
|
exports.makeApiRequest = makeApiRequest;
|
|
8
8
|
exports.usePrevious = usePrevious;
|
|
9
|
-
|
|
10
9
|
var _react = require("react");
|
|
11
|
-
|
|
12
10
|
async function makeApiRequest(path) {
|
|
13
11
|
try {
|
|
14
12
|
const response = await fetch(`https://api.binance.com/${path}`);
|
|
@@ -17,10 +15,8 @@ async function makeApiRequest(path) {
|
|
|
17
15
|
throw new Error(`Binance request error: ${error.status}`);
|
|
18
16
|
}
|
|
19
17
|
}
|
|
20
|
-
|
|
21
18
|
async function getAllSymbols(symbol) {
|
|
22
19
|
let newSymbols = [];
|
|
23
|
-
|
|
24
20
|
try {
|
|
25
21
|
const data = await makeApiRequest(`api/v3/exchangeInfo?symbol=${symbol.toUpperCase()}`);
|
|
26
22
|
data.symbols.forEach(item => {
|
|
@@ -38,10 +34,8 @@ async function getAllSymbols(symbol) {
|
|
|
38
34
|
} catch (e) {
|
|
39
35
|
return newSymbols;
|
|
40
36
|
}
|
|
41
|
-
|
|
42
37
|
return newSymbols;
|
|
43
38
|
}
|
|
44
|
-
|
|
45
39
|
function usePrevious(value) {
|
|
46
40
|
const ref = (0, _react.useRef)();
|
|
47
41
|
(0, _react.useEffect)(() => {
|
package/dist/components/index.js
CHANGED
|
@@ -9,7 +9,5 @@ Object.defineProperty(exports, "TVChartContainer", {
|
|
|
9
9
|
return _TVChartContainer.default;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
-
|
|
13
12
|
var _TVChartContainer = _interopRequireDefault(require("./TVChartContainer"));
|
|
14
|
-
|
|
15
13
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -6,32 +6,25 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.subscribeOnStream = subscribeOnStream;
|
|
7
7
|
exports.unsubscribeFromStream = unsubscribeFromStream;
|
|
8
8
|
const channelToSubscription = new Map();
|
|
9
|
-
|
|
10
9
|
function setupSockets(subRequest) {
|
|
11
10
|
const socket = new WebSocket("wss://stream.binance.com:9443/ws");
|
|
12
11
|
window.socket = socket;
|
|
13
|
-
|
|
14
12
|
socket.onopen = event => {
|
|
15
13
|
console.log("[socket] Connected");
|
|
16
14
|
socket.send(JSON.stringify(subRequest));
|
|
17
15
|
};
|
|
18
|
-
|
|
19
16
|
socket.onclose = reason => {
|
|
20
17
|
console.log("[socket] Disconnected:", reason);
|
|
21
18
|
};
|
|
22
|
-
|
|
23
19
|
socket.onerror = error => {
|
|
24
20
|
console.log("[socket] Error:", error);
|
|
25
21
|
};
|
|
26
|
-
|
|
27
22
|
socket.onmessage = e => {
|
|
28
23
|
const data = JSON.parse(e.data);
|
|
29
|
-
|
|
30
24
|
if (data.e == undefined) {
|
|
31
25
|
// skip all non-TRADE events
|
|
32
26
|
return;
|
|
33
27
|
}
|
|
34
|
-
|
|
35
28
|
const {
|
|
36
29
|
s: symbol,
|
|
37
30
|
t: startTime,
|
|
@@ -47,11 +40,9 @@ function setupSockets(subRequest) {
|
|
|
47
40
|
} = data.k;
|
|
48
41
|
const channelString = `${symbol.toLowerCase()}@kline_${interval}`;
|
|
49
42
|
const subscriptionItem = channelToSubscription.get(channelString);
|
|
50
|
-
|
|
51
43
|
if (subscriptionItem === undefined) {
|
|
52
44
|
return;
|
|
53
45
|
}
|
|
54
|
-
|
|
55
46
|
const bar = {
|
|
56
47
|
time: startTime,
|
|
57
48
|
open: open,
|
|
@@ -59,12 +50,11 @@ function setupSockets(subRequest) {
|
|
|
59
50
|
low: low,
|
|
60
51
|
close: close,
|
|
61
52
|
volume: volume
|
|
62
|
-
};
|
|
63
|
-
|
|
53
|
+
};
|
|
54
|
+
// send data to every subscriber of that symbol
|
|
64
55
|
subscriptionItem.handlers.forEach(handler => handler.callback(bar));
|
|
65
56
|
};
|
|
66
57
|
}
|
|
67
|
-
|
|
68
58
|
function subscribeOnStream(symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback, interval) {
|
|
69
59
|
const channelString = `${symbolInfo.name.toLowerCase()}@kline_${interval}`;
|
|
70
60
|
const handler = {
|
|
@@ -72,13 +62,11 @@ function subscribeOnStream(symbolInfo, resolution, onRealtimeCallback, subscribe
|
|
|
72
62
|
callback: onRealtimeCallback
|
|
73
63
|
};
|
|
74
64
|
let subscriptionItem = channelToSubscription.get(channelString);
|
|
75
|
-
|
|
76
65
|
if (subscriptionItem) {
|
|
77
66
|
// already subscribed to the channel, use the existing subscription
|
|
78
67
|
subscriptionItem.handlers.push(handler);
|
|
79
68
|
return;
|
|
80
69
|
}
|
|
81
|
-
|
|
82
70
|
subscriptionItem = {
|
|
83
71
|
subscribeUID,
|
|
84
72
|
resolution,
|
|
@@ -92,17 +80,14 @@ function subscribeOnStream(symbolInfo, resolution, onRealtimeCallback, subscribe
|
|
|
92
80
|
channelToSubscription.set(channelString, subscriptionItem);
|
|
93
81
|
setupSockets(subRequest);
|
|
94
82
|
}
|
|
95
|
-
|
|
96
83
|
function unsubscribeFromStream(subscriberUID) {
|
|
97
84
|
// find a subscription with id === subscriberUID
|
|
98
85
|
for (const channelString of channelToSubscription.keys()) {
|
|
99
86
|
const subscriptionItem = channelToSubscription.get(channelString);
|
|
100
87
|
const handlerIndex = subscriptionItem.handlers.findIndex(handler => handler.id === subscriberUID);
|
|
101
|
-
|
|
102
88
|
if (handlerIndex !== -1) {
|
|
103
89
|
// remove from handlers
|
|
104
90
|
subscriptionItem.handlers.splice(handlerIndex, 1);
|
|
105
|
-
|
|
106
91
|
if (subscriptionItem.handlers.length === 0) {
|
|
107
92
|
// unsubscribe from the channel, if it was the last handler
|
|
108
93
|
console.log("[unsubscribeBars]: Unsubscribe from streaming. Channel:", channelString);
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.3.
|
|
2
|
+
"version": "0.3.2",
|
|
3
3
|
"name": "binbot-charts",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"react": "^17.0.1",
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
"@babel/core": "^7.18.13",
|
|
12
12
|
"@babel/polyfill": "^7.12.1",
|
|
13
13
|
"@babel/preset-env": "^7.19.0",
|
|
14
|
-
"react
|
|
14
|
+
"@types/react": "^18.0.26",
|
|
15
|
+
"@types/react-dom": "^18.0.10",
|
|
16
|
+
"immer": "^9.0.17",
|
|
17
|
+
"react-scripts": "^5.0.1",
|
|
18
|
+
"typescript": "^4.9.4"
|
|
15
19
|
},
|
|
16
20
|
"scripts": {
|
|
17
21
|
"start": "react-scripts start",
|