binbot-charts 0.5.2 → 0.5.4

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.
@@ -0,0 +1,153 @@
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;
@@ -0,0 +1,45 @@
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
+ }
@@ -0,0 +1,106 @@
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
+ }
@@ -1,32 +1,10 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
4
  };
28
5
  Object.defineProperty(exports, "__esModule", { value: true });
29
- const react_1 = __importStar(require("react"));
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
30
8
  const use_immer_1 = require("use-immer");
31
9
  require("./App.css");
32
10
  const TVChartContainer_1 = __importDefault(require("./components/TVChartContainer"));
@@ -96,11 +74,6 @@ function App() {
96
74
  setSymbolState(e.target.value);
97
75
  }
98
76
  };
99
- return (<>
100
- <h1 style={{ textAlign: "center" }}>Test chart</h1>
101
- <label htmlFor="symbol">Type symbol</label>
102
- <input name="symbol" type="text" onChange={handleChange}/>
103
- <TVChartContainer_1.default symbol={symbolState} interval={"1h"} timescaleMarks={testTimeMarks} orderLines={orderLines} onTick={handleTick} getLatestBar={getLatestBar}/>
104
- </>);
77
+ 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 })] }));
105
78
  }
106
79
  exports.default = App;