binbot-charts 0.5.4 → 0.5.7
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/dist/src/App.js +5 -3
- package/dist/src/components/index.js +1 -2
- package/dist/src/index.js +7 -4
- package/package.json +4 -4
- package/dist/components/datafeed.js +0 -153
- package/dist/components/helpers.js +0 -45
- package/dist/components/streaming.js +0 -106
package/dist/src/App.js
CHANGED
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.App = void 0;
|
|
6
7
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
8
|
const react_1 = require("react");
|
|
8
9
|
const use_immer_1 = require("use-immer");
|
|
@@ -19,7 +20,7 @@ function roundTime(ts) {
|
|
|
19
20
|
const roundFloor = time.getTime();
|
|
20
21
|
return roundFloor / 1000;
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
+
const App = () => {
|
|
23
24
|
const [currentPrice, setCurrentPrice] = (0, react_1.useState)(null);
|
|
24
25
|
const [orderLines, setOrderLines] = (0, use_immer_1.useImmer)([]);
|
|
25
26
|
const [symbolState, setSymbolState] = (0, react_1.useState)("BTCUSDT");
|
|
@@ -75,5 +76,6 @@ function App() {
|
|
|
75
76
|
}
|
|
76
77
|
};
|
|
77
78
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h1", Object.assign({ style: { textAlign: "center" } }, { children: "Test chart" })), (0, jsx_runtime_1.jsx)("label", Object.assign({ htmlFor: "symbol" }, { children: "Type symbol" })), (0, jsx_runtime_1.jsx)("input", { name: "symbol", type: "text", onChange: handleChange }), (0, jsx_runtime_1.jsx)(TVChartContainer_1.default, { symbol: symbolState, interval: "1h", timescaleMarks: testTimeMarks, orderLines: orderLines, onTick: handleTick, getLatestBar: getLatestBar })] }));
|
|
78
|
-
}
|
|
79
|
-
exports.
|
|
79
|
+
};
|
|
80
|
+
exports.App = App;
|
|
81
|
+
exports.default = exports.App;
|
|
@@ -3,6 +3,5 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.TVChartContainer = void 0;
|
|
7
6
|
const TVChartContainer_1 = __importDefault(require("./TVChartContainer"));
|
|
8
|
-
exports.
|
|
7
|
+
exports.default = TVChartContainer_1.default;
|
package/dist/src/index.js
CHANGED
|
@@ -4,8 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const App_tsx_1 = __importDefault(require("./App.tsx"));
|
|
7
|
+
const client_1 = require("react-dom/client");
|
|
8
|
+
const App_1 = __importDefault(require("./App")); // Ensure App is a default export from "./App"
|
|
10
9
|
require("./index.css");
|
|
11
|
-
|
|
10
|
+
const rootElement = document.getElementById("root");
|
|
11
|
+
if (rootElement) {
|
|
12
|
+
const root = (0, client_1.createRoot)(rootElement);
|
|
13
|
+
root.render((0, jsx_runtime_1.jsx)(App_1.default, {}));
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.5.
|
|
2
|
+
"version": "0.5.7",
|
|
3
3
|
"name": "binbot-charts",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"react": "^
|
|
6
|
-
"react-dom": "^
|
|
5
|
+
"react": "^18.3.1",
|
|
6
|
+
"react-dom": "^18.3.1",
|
|
7
7
|
"use-immer": "^0.10.0"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"start": "react-scripts start",
|
|
23
|
-
"build": "rm -rf dist && NODE_ENV=production
|
|
23
|
+
"build": "rm -rf dist && NODE_ENV=production tsc && cp -r src/charting_library dist/charting_library && tsc",
|
|
24
24
|
"release": "yarn build && yarn publish"
|
|
25
25
|
},
|
|
26
26
|
"description": "Binbot charts is the default candlestick bars chart used in terminal.binbot.in to render bots graphically.",
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
var _helpers = require("./helpers.js");
|
|
8
|
-
var _streaming = require("./streaming.js");
|
|
9
|
-
const binanceResolutions = ["1s", "1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "12h", "1d", "3d", "1w", "1M"];
|
|
10
|
-
const getConfigurationData = async () => {
|
|
11
|
-
return {
|
|
12
|
-
supports_marks: true,
|
|
13
|
-
supports_time: true,
|
|
14
|
-
supports_timescale_marks: true,
|
|
15
|
-
supports_time: true,
|
|
16
|
-
supported_resolutions: ["1S", "1", "3", "5", "15", "30", "60", "120", "240", "360", "480", "720", "1D", "3D", "1W", "12M"],
|
|
17
|
-
exchanges: [{
|
|
18
|
-
value: "Binance",
|
|
19
|
-
name: "Binance",
|
|
20
|
-
desc: "Binance"
|
|
21
|
-
}],
|
|
22
|
-
symbols_types: [{
|
|
23
|
-
name: "crypto",
|
|
24
|
-
value: "crypto"
|
|
25
|
-
}]
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @param timescale { Array }. timescaleMark objects
|
|
31
|
-
* @param interval { string }. Klines timescale from the list of Binance Enums
|
|
32
|
-
*/
|
|
33
|
-
class Datafeed {
|
|
34
|
-
constructor() {
|
|
35
|
-
let timescaleMarks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
36
|
-
let interval = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "1h";
|
|
37
|
-
this.streaming = null;
|
|
38
|
-
this.timescaleMarks = timescaleMarks;
|
|
39
|
-
this.interval = interval;
|
|
40
|
-
}
|
|
41
|
-
onReady = async callback => {
|
|
42
|
-
this.configurationData = await getConfigurationData();
|
|
43
|
-
callback(this.configurationData);
|
|
44
|
-
};
|
|
45
|
-
searchSymbols = async (userInput, exchange, symbolType, onResultReadyCallback) => {
|
|
46
|
-
const symbols = await (0, _helpers.getAllSymbols)(userInput);
|
|
47
|
-
onResultReadyCallback(symbols);
|
|
48
|
-
};
|
|
49
|
-
resolveSymbol = async (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
|
|
50
|
-
if (!symbolName) {
|
|
51
|
-
await onResolveErrorCallback("cannot resolve symbol");
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const symbolInfo = () => {
|
|
55
|
-
return {
|
|
56
|
-
ticker: symbolName,
|
|
57
|
-
name: symbolName,
|
|
58
|
-
ticker: symbolName,
|
|
59
|
-
description: symbolName,
|
|
60
|
-
type: "crypto",
|
|
61
|
-
session: "24x7",
|
|
62
|
-
timezone: "Etc/UTC",
|
|
63
|
-
exchange: "Binance",
|
|
64
|
-
minmov: 100,
|
|
65
|
-
pricescale: 100000,
|
|
66
|
-
has_daily: true,
|
|
67
|
-
has_intraday: true,
|
|
68
|
-
has_no_volume: false,
|
|
69
|
-
has_seconds: true,
|
|
70
|
-
seconds_multipliers: [1],
|
|
71
|
-
volume: "hundreds",
|
|
72
|
-
volume_precision: 9,
|
|
73
|
-
data_status: "streaming",
|
|
74
|
-
resolution: "1h"
|
|
75
|
-
};
|
|
76
|
-
};
|
|
77
|
-
const symbol = await symbolInfo();
|
|
78
|
-
onSymbolResolvedCallback(symbol);
|
|
79
|
-
};
|
|
80
|
-
getBars = async (symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) => {
|
|
81
|
-
const {
|
|
82
|
-
from,
|
|
83
|
-
to,
|
|
84
|
-
firstDataRequest
|
|
85
|
-
} = periodParams;
|
|
86
|
-
let interval = "60"; // 1 hour
|
|
87
|
-
// Calculate interval using resolution data
|
|
88
|
-
if (!/[a-zA-Z]$/.test(resolution)) {
|
|
89
|
-
if (parseInt(resolution) >= 60) {
|
|
90
|
-
interval = parseInt(resolution) / 60 + "h";
|
|
91
|
-
} else {
|
|
92
|
-
interval = resolution + "m";
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
interval = resolution.toLowerCase().replace(/[a-z]\b/g, c => c.toLowerCase());
|
|
96
|
-
}
|
|
97
|
-
let urlParameters = {
|
|
98
|
-
symbol: symbolInfo.name,
|
|
99
|
-
interval: interval,
|
|
100
|
-
startTime: Math.abs(from * 1000),
|
|
101
|
-
endTime: Math.abs(to * 1000),
|
|
102
|
-
limit: 600
|
|
103
|
-
};
|
|
104
|
-
const query = Object.keys(urlParameters).map(name => `${name}=${encodeURIComponent(urlParameters[name])}`).join("&");
|
|
105
|
-
try {
|
|
106
|
-
const data = await (0, _helpers.makeApiRequest)(`api/v3/uiKlines?${query}`);
|
|
107
|
-
if (data.Response && data.Response === "Error" || data.length === 0) {
|
|
108
|
-
// "noData" should be set if there is no data in the requested period.
|
|
109
|
-
onHistoryCallback([], {
|
|
110
|
-
noData: true
|
|
111
|
-
});
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
let bars = [];
|
|
115
|
-
data.forEach(bar => {
|
|
116
|
-
if (bar[0] >= from * 1000 && bar[0] < to * 1000) {
|
|
117
|
-
bars = [...bars, {
|
|
118
|
-
time: bar[0],
|
|
119
|
-
low: bar[3],
|
|
120
|
-
high: bar[2],
|
|
121
|
-
open: bar[1],
|
|
122
|
-
close: bar[4],
|
|
123
|
-
volume: bar[5]
|
|
124
|
-
}];
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
onHistoryCallback(bars, {
|
|
128
|
-
noData: false
|
|
129
|
-
});
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.log("[getBars]: Get error", error);
|
|
132
|
-
onErrorCallback(error);
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
getTimescaleMarks(symbolInfo, from, to, onDataCallback, resolution) {
|
|
136
|
-
if (this.timescaleMarks.length > 0) {
|
|
137
|
-
let timescaleMarks = Object.assign([], this.timescaleMarks);
|
|
138
|
-
onDataCallback(timescaleMarks);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
async getServerTime(onServertimeCallback) {
|
|
142
|
-
const data = await (0, _helpers.makeApiRequest)(`api/v3/time`);
|
|
143
|
-
const serverTime = data.serverTime / 1000;
|
|
144
|
-
onServertimeCallback(serverTime);
|
|
145
|
-
}
|
|
146
|
-
subscribeBars = (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {
|
|
147
|
-
(0, _streaming.subscribeOnStream)(symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback, this.interval);
|
|
148
|
-
};
|
|
149
|
-
unsubscribeBars = subscriberUID => {
|
|
150
|
-
(0, _streaming.unsubscribeFromStream)(subscriberUID);
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
exports.default = Datafeed;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.getAllSymbols = getAllSymbols;
|
|
7
|
-
exports.makeApiRequest = makeApiRequest;
|
|
8
|
-
exports.usePrevious = usePrevious;
|
|
9
|
-
var _react = require("react");
|
|
10
|
-
async function makeApiRequest(path) {
|
|
11
|
-
try {
|
|
12
|
-
const response = await fetch(`https://api.binance.com/${path}`);
|
|
13
|
-
return response.json();
|
|
14
|
-
} catch (error) {
|
|
15
|
-
throw new Error(`Binance request error: ${error.status}`);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
async function getAllSymbols(symbol) {
|
|
19
|
-
let newSymbols = [];
|
|
20
|
-
try {
|
|
21
|
-
const data = await makeApiRequest(`api/v3/exchangeInfo?symbol=${symbol.toUpperCase()}`);
|
|
22
|
-
data.symbols.forEach(item => {
|
|
23
|
-
if (item.status === "TRADING") {
|
|
24
|
-
newSymbols.push({
|
|
25
|
-
symbol: item.symbol,
|
|
26
|
-
full_name: `${item.baseAsset}/${item.quoteAsset}`,
|
|
27
|
-
description: `Precision: ${item.quoteAssetPrecision}`,
|
|
28
|
-
exchange: "Binance",
|
|
29
|
-
ticker: item.symbol,
|
|
30
|
-
type: "crypto"
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
} catch (e) {
|
|
35
|
-
return newSymbols;
|
|
36
|
-
}
|
|
37
|
-
return newSymbols;
|
|
38
|
-
}
|
|
39
|
-
function usePrevious(value) {
|
|
40
|
-
const ref = (0, _react.useRef)();
|
|
41
|
-
(0, _react.useEffect)(() => {
|
|
42
|
-
ref.current = value;
|
|
43
|
-
});
|
|
44
|
-
return ref.current;
|
|
45
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.subscribeOnStream = subscribeOnStream;
|
|
7
|
-
exports.unsubscribeFromStream = unsubscribeFromStream;
|
|
8
|
-
const channelToSubscription = new Map();
|
|
9
|
-
function setupSockets(subRequest) {
|
|
10
|
-
const socket = new WebSocket("wss://stream.binance.com:9443/ws");
|
|
11
|
-
window.socket = socket;
|
|
12
|
-
socket.onopen = event => {
|
|
13
|
-
console.log("[socket] Connected");
|
|
14
|
-
socket.send(JSON.stringify(subRequest));
|
|
15
|
-
};
|
|
16
|
-
socket.onclose = reason => {
|
|
17
|
-
console.log("[socket] Disconnected:", reason);
|
|
18
|
-
};
|
|
19
|
-
socket.onerror = error => {
|
|
20
|
-
console.log("[socket] Error:", error);
|
|
21
|
-
};
|
|
22
|
-
socket.onmessage = e => {
|
|
23
|
-
const data = JSON.parse(e.data);
|
|
24
|
-
if (data.e == undefined) {
|
|
25
|
-
// skip all non-TRADE events
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const {
|
|
29
|
-
s: symbol,
|
|
30
|
-
t: startTime,
|
|
31
|
-
T: closeTime,
|
|
32
|
-
i: interval,
|
|
33
|
-
o: open,
|
|
34
|
-
c: close,
|
|
35
|
-
h: high,
|
|
36
|
-
l: low,
|
|
37
|
-
v: volume,
|
|
38
|
-
n: trades,
|
|
39
|
-
q: quoteVolume
|
|
40
|
-
} = data.k;
|
|
41
|
-
const channelString = `${symbol.toLowerCase()}@kline_${interval}`;
|
|
42
|
-
const subscriptionItem = channelToSubscription.get(channelString);
|
|
43
|
-
if (subscriptionItem === undefined) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const bar = {
|
|
47
|
-
time: startTime,
|
|
48
|
-
open: open,
|
|
49
|
-
high: high,
|
|
50
|
-
low: low,
|
|
51
|
-
close: close,
|
|
52
|
-
volume: volume
|
|
53
|
-
};
|
|
54
|
-
// send data to every subscriber of that symbol
|
|
55
|
-
subscriptionItem.handlers.forEach(handler => handler.callback(bar));
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function subscribeOnStream(symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback, interval) {
|
|
59
|
-
const channelString = `${symbolInfo.name.toLowerCase()}@kline_${interval}`;
|
|
60
|
-
const handler = {
|
|
61
|
-
id: subscribeUID,
|
|
62
|
-
callback: onRealtimeCallback
|
|
63
|
-
};
|
|
64
|
-
let subscriptionItem = channelToSubscription.get(channelString);
|
|
65
|
-
if (subscriptionItem) {
|
|
66
|
-
// already subscribed to the channel, use the existing subscription
|
|
67
|
-
subscriptionItem.handlers.push(handler);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
subscriptionItem = {
|
|
71
|
-
subscribeUID,
|
|
72
|
-
resolution,
|
|
73
|
-
handlers: [handler]
|
|
74
|
-
};
|
|
75
|
-
const subRequest = {
|
|
76
|
-
method: "SUBSCRIBE",
|
|
77
|
-
params: [channelString],
|
|
78
|
-
id: 1
|
|
79
|
-
};
|
|
80
|
-
channelToSubscription.set(channelString, subscriptionItem);
|
|
81
|
-
setupSockets(subRequest);
|
|
82
|
-
}
|
|
83
|
-
function unsubscribeFromStream(subscriberUID) {
|
|
84
|
-
// find a subscription with id === subscriberUID
|
|
85
|
-
for (const channelString of channelToSubscription.keys()) {
|
|
86
|
-
const subscriptionItem = channelToSubscription.get(channelString);
|
|
87
|
-
const handlerIndex = subscriptionItem.handlers.findIndex(handler => handler.id === subscriberUID);
|
|
88
|
-
if (handlerIndex !== -1) {
|
|
89
|
-
// remove from handlers
|
|
90
|
-
subscriptionItem.handlers.splice(handlerIndex, 1);
|
|
91
|
-
if (subscriptionItem.handlers.length === 0) {
|
|
92
|
-
// unsubscribe from the channel, if it was the last handler
|
|
93
|
-
console.log("[unsubscribeBars]: Unsubscribe from streaming. Channel:", channelString);
|
|
94
|
-
const subRequest = {
|
|
95
|
-
method: "UNSUBSCRIBE",
|
|
96
|
-
params: [channelString],
|
|
97
|
-
id: 1
|
|
98
|
-
};
|
|
99
|
-
window.socket.send(JSON.stringify(subRequest));
|
|
100
|
-
channelToSubscription.delete(channelString);
|
|
101
|
-
window.socket = undefined;
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|