dccd 2.0.0__py3-none-any.whl

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.
dccd/__init__.py ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+ # @Author: ArthurBernard
4
+ # @Email: arthur.bernard.92@gmail.com
5
+ # @Date: 2019-07-26 16:54:02
6
+ # @Last modified by: ArthurBernard
7
+ # @Last modified time: 2026-05-12
8
+
9
+ """ This is `dccd` package.
10
+
11
+ It allows you to download data (prices, volumes, trades, orderbooks, etc.)
12
+ from crypto-currency exchanges (currently Binance, Bitfinex, Bitmex, Coinbase,
13
+ and Kraken).
14
+
15
+ """
16
+
17
+ from importlib.metadata import PackageNotFoundError, version
18
+
19
+ try:
20
+ __version__ = version("dccd")
21
+ except PackageNotFoundError:
22
+ __version__ = "unknown"
23
+
24
+ __all__ = ['__version__']
25
+
26
+ # ======= #
27
+ # Tools #
28
+ # ======= #
29
+
30
+ # ===== #
31
+ # New #
32
+ # ===== #
33
+ from . import continuous_dl, histo_dl
34
+ from .continuous_dl import *
35
+ from .histo_dl import *
36
+ from .models import OHLCBar, OrderBookEntry, Trade
37
+ from .tools import date_time, io
38
+
39
+ __all__ += ['date_time']
40
+ __all__ += ['io']
41
+ __all__ += ['process_data']
42
+ __all__ += continuous_dl.__all__
43
+ __all__ += histo_dl.__all__
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+ # @Author: ArthurBernard
4
+ # @Email: arthur.bernard.92@gmail.com
5
+ # @Date: 2019-08-30 09:46:41
6
+ # @Last modified by: ArthurBernard
7
+ # @Last modified time: 2019-09-03 22:26:18
8
+
9
+ """ Module to download continuously data.
10
+
11
+ Module to download continuously data (orderbook, trades, etc.) and update
12
+ automatically the database. *Currently only supports Bitfinex and Bitmex
13
+ exchanges.*
14
+
15
+ .. currentmodule:: dccd.continuous_dl
16
+
17
+ .. toctree::
18
+ :maxdepth: 1
19
+ :caption: Contents:
20
+
21
+ continuous_dl.bitfinex
22
+ continuous_dl.bitmex
23
+
24
+ """
25
+
26
+ # Built-in packages
27
+
28
+ # Third party packages
29
+
30
+ # Local packages
31
+ from . import bitfinex, bitmex, bybit, exchange
32
+ from .bitfinex import *
33
+ from .bitmex import *
34
+ from .bybit import *
35
+
36
+ __all__ = ['exchange']
37
+ __all__ += bitfinex.__all__
38
+ __all__ += bitmex.__all__
39
+ __all__ += bybit.__all__
@@ -0,0 +1,441 @@
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+ # @Author: ArthurBernard
4
+ # @Email: arthur.bernard.92@gmail.com
5
+ # @Date: 2019-03-25 19:31:56
6
+ # @Last modified by: ArthurBernard
7
+ # @Last modified time: 2019-09-11 08:47:31
8
+
9
+ """ Objects and functions to download data from Bitfinex exchange.
10
+
11
+ .. currentmodule:: dccd.continuous_dl.bitfinex
12
+
13
+ These functions and objects allow you to continuously download data and update
14
+ your database.
15
+
16
+ High level API
17
+ --------------
18
+
19
+ .. autofunction:: get_data_bitfinex
20
+ .. autofunction:: get_orderbook_bitfinex
21
+ .. autofunction:: get_trades_bitfinex
22
+
23
+ Low level API
24
+ -------------
25
+
26
+ .. autoclass:: dccd.continuous_dl.bitfinex.DownloadBitfinexData
27
+ :members: set_process_data, set_saver
28
+ :special-members: __call__
29
+ :show-inheritance:
30
+
31
+ """
32
+
33
+ # Built-in packages
34
+ import asyncio
35
+ import logging
36
+ import time
37
+
38
+ from dccd.continuous_dl.exchange import ContinuousDownloader
39
+ from dccd.process_data import set_marketdepth, set_ohlc, set_orders, set_trades
40
+
41
+ # Third party packages
42
+ # Local packages
43
+ from dccd.tools.io import IODataBase
44
+
45
+ __all__ = [
46
+ 'DownloadBitfinexData', 'get_data_bitfinex', 'get_orderbook_bitfinex',
47
+ 'get_trades_bitfinex',
48
+ ]
49
+
50
+ # TODO : - get_raw_orderbook; get_ohlc;
51
+
52
+ # =========================================================================== #
53
+ # Parser functions #
54
+ # =========================================================================== #
55
+
56
+
57
+ def _parser_trades(tData):
58
+ if tData[1] == 'te':
59
+ tData = tData[2]
60
+
61
+ return {
62
+ 'tid': tData[0],
63
+ 'timestamp': tData[1] / 1000,
64
+ 'price': tData[3],
65
+ 'amount': abs(tData[2]),
66
+ 'type': 'buy' if tData[2] > 0. else 'sell',
67
+ }
68
+
69
+
70
+ def _parser_book(tData):
71
+ if isinstance(tData[1], list):
72
+ tData = tData[1]
73
+
74
+ return {'price': str(tData[0]), 'count': tData[1], 'amount': tData[2]}
75
+
76
+
77
+ # =========================================================================== #
78
+ # Download objects #
79
+ # =========================================================================== #
80
+
81
+
82
+ class DownloadBitfinexData(ContinuousDownloader):
83
+ """ Basis object to download data from a stream websocket client API.
84
+
85
+ Parameters
86
+ ----------
87
+ time_step : int, optional
88
+ Number of seconds between two snapshots of data, minimum is 1, default
89
+ is 60 (one minute). Each `time_step` data will be processed and updated
90
+ to the database.
91
+ until : int, optional
92
+ Number of seconds before stoping or timestamp of when stoping, default
93
+ is 3600 (one hour).
94
+
95
+ Attributes
96
+ ----------
97
+ host : str
98
+ Adress of host to connect.
99
+ conn_par : dict
100
+ Parameters of websocket connection.
101
+ ws : websockets.client.WebSocketClientProtocol
102
+ Connection with the websocket client.
103
+ is_connect : bool
104
+ True if is connected, False otherwise.
105
+ ts : int
106
+ Number of second between two snapshots of data.
107
+ t : int
108
+ Current timestamp but rounded by `ts`.
109
+ until : int
110
+ Timestamp to stop to download data.
111
+
112
+ Methods
113
+ -------
114
+ set_process_data
115
+ set_saver
116
+ __call__
117
+
118
+ """
119
+
120
+ # TODO :
121
+ # - None time_step send tick by tick data
122
+ # - Clean private/public methods
123
+ # - Add optional setting parser
124
+ # TODO : docstring
125
+ # TODO : add more parser methods
126
+
127
+ def __init__(self, time_step=60, until=3600):
128
+ """ Initialize object. """
129
+ # TODO : set until parser to convert date, time, etc
130
+ if until is None:
131
+ until = 0
132
+
133
+ elif until > time.time():
134
+ until -= int(time.time())
135
+
136
+ ContinuousDownloader.__init__(self, 'bitfinex', time_step=time_step,
137
+ STOP=until)
138
+
139
+ self._parser_data = {
140
+ 'book': self.parser_book,
141
+ 'book_raw': self.parser_raw_book,
142
+ 'trades': self.parser_trades,
143
+ 'trades_raw': self.parser_raw_trades,
144
+ # 'candles': None,
145
+ }
146
+ self.logger = logging.getLogger(__name__)
147
+ self.d = {}
148
+
149
+ def parser_raw_book(self, data):
150
+ """ Parse raw order book, each timestep set in a list all orders.
151
+
152
+ Parameters
153
+ ----------
154
+ data : list
155
+ Order data.
156
+
157
+ """
158
+ data = _parser_book(data)
159
+
160
+ self._raw_parser(data)
161
+
162
+ def parser_book(self, data):
163
+ """ Parse market depth of order book.
164
+
165
+ Parameters
166
+ ----------
167
+ data : list
168
+ Order data.
169
+
170
+ """
171
+ data = _parser_book(data)
172
+
173
+ if data['count'] > 0:
174
+ if data['price'] in self.d.keys():
175
+ self.d[data['price']]['amount'] += data['amount']
176
+
177
+ else:
178
+ self.d[data['price']] = data
179
+
180
+ else:
181
+ self.d.pop(data['price'])
182
+
183
+ self._data[self.t] = {v['price']: v['amount'] for v in self.d.values()}
184
+
185
+ def parser_raw_trades(self, data):
186
+ """ Parse trade data.
187
+
188
+ Parameters
189
+ ----------
190
+ data : list
191
+ Trade data.
192
+
193
+ """
194
+ if data[1] == 'tu':
195
+
196
+ return
197
+
198
+ data = _parser_trades(data)
199
+
200
+ self._raw_parser(data)
201
+
202
+ def parser_trades(self, data):
203
+ """ Parse OHLC data.
204
+
205
+ Parameters
206
+ ----------
207
+ data : list
208
+ Trade data.
209
+
210
+ """
211
+ # TODO : process ohlc
212
+ if data[1] == 'tu':
213
+
214
+ return
215
+
216
+ data = _parser_trades(data)
217
+
218
+ self._raw_parser(data)
219
+
220
+ async def on_message(self, data):
221
+ """ Set data to order book. """
222
+ if isinstance(data, list):
223
+ if data[1] == 'hb':
224
+ self.logger.info('HeartBeat')
225
+
226
+ elif isinstance(data[1][0], list):
227
+
228
+ for d in data[1]:
229
+ self.parser(d)
230
+
231
+ else:
232
+ self.parser(data)
233
+
234
+ else:
235
+ self.logger.info('{}'.format(data))
236
+
237
+ def __call__(self, channel, **kwargs):
238
+ """ Open a websocket connection and save/update the database.
239
+
240
+ Run asynchronously two loops to get data from bitfinex websocket and
241
+ save/update the database.
242
+
243
+ Parameters
244
+ ----------
245
+ channel : {'book', 'book_raw', 'trades', 'trades_raw'}
246
+ Channel to get data, by default data will be aggregated (OHLC for
247
+ 'trades' and reconstructed orderbook for 'book'), add '_raw' to the
248
+ `channel` to get raw data (trade tick by tick or each orders).
249
+ **kwargs
250
+ Any revelevant keyword arguments will be passed to the websocket
251
+ connector, see API documentation [1]_ for more details.
252
+
253
+ Warnings
254
+ --------
255
+ 'book_raw' and 'trades_raw' can be very memory expensive.
256
+
257
+ References
258
+ ----------
259
+ .. [1] https://docs.bitfinex.com/v2/docs/ws-public
260
+
261
+ """
262
+ self.parser = self.get_parser(channel)
263
+
264
+ channel = channel[:-4] if channel[-4:] == '_raw' else channel
265
+
266
+ self.logger.info('Try connect WS and set {} stream.'.format(channel))
267
+
268
+ self.loop = asyncio.get_event_loop()
269
+ self.loop.run_until_complete(asyncio.gather(
270
+ self._connect(channel=channel, **kwargs),
271
+ self._loop()
272
+ ))
273
+
274
+ return self
275
+
276
+
277
+ # =========================================================================== #
278
+ # High level functions #
279
+ # =========================================================================== #
280
+
281
+ # TODO : Finish docstring
282
+
283
+
284
+ def get_data_bitfinex(channel, process_func, process_params={},
285
+ save_method='dataframe', io_params={}, time_step=60,
286
+ until=None, path=None, **kwargs):
287
+ """ Download data from Bitfinex exchange and update the database.
288
+
289
+ Parameters
290
+ ----------
291
+ channel : str, {'book', 'book_raw', 'trades', 'trades_raw'}
292
+ Websocket channel to get data, by default data will be aggregated (OHLC
293
+ for 'trades' and reconstructed orderbook for 'book'), add '_raw' to the
294
+ `channel` to get raw data (trade tick by tick or each orders).
295
+ process_func : callable
296
+ Function to process and clean data before to be saved. Must take `data`
297
+ in arguments and can take any optional keywords arguments, cf function
298
+ exemples in :mod:`dccd.process_data`.
299
+ process_params : dict, optional
300
+ Dictionary of the keyword arguments available to `process_func`, cf
301
+ documentation into :mod:`dccd.process_data`.
302
+ save_method : {'DataFrame', 'SQLite', 'CSV', 'Excel', 'PostgreSQL',\
303
+ 'Oracle', 'MSSQL', 'MySQL'},
304
+ It will create an IODataBase object to save/update the database in the
305
+ specified format `save_method`, default is 'DataFrame' it save as
306
+ binary pd.DataFrame object. More informations are available into
307
+ :mod:`dccd.tools.io`.
308
+ io_params : dict, optional
309
+ Dictionary of the keyword arguments available to the
310
+ ``dccd.tools.io.IODataBase`` callable method. Note: With SQL format
311
+ some parameters are compulsory, see details into :mod:`dccd.tools.io`.
312
+ time_step : int, optional
313
+ Number of second between two snapshots of data, default 60 (1 minute).
314
+ until : int, optional
315
+ Number of seconds before stoping to download and update, default is
316
+ None. If `until` equal 0 or None it means it never stop.
317
+ path : str, optional
318
+ Path to save/update the database, default is None. If `path` is None,
319
+ database is saved at the relative path './database/bitfinex/`channel`'.
320
+ **kwargs
321
+ Any revelevant keyword arguments will be passed to the websocket
322
+ connector, see Bitfinex API documentation [2]_ for more details.
323
+
324
+ Warnings
325
+ --------
326
+ 'book_raw' and 'trades_raw' can be very memory expensive.
327
+
328
+ See Also
329
+ --------
330
+ process_data : function to process/clean data (set_marketdepth, set_ohlc,
331
+ set_orders, set_marketdepth).
332
+ tools.io.IODataBase : object to save/update the database with respect to
333
+ specified format.
334
+
335
+ References
336
+ ----------
337
+ .. [2] https://docs.bitfinex.com/v2/docs/ws-public
338
+
339
+ """
340
+ # Set database connector object
341
+ if path is None:
342
+ path = './database/bitfinex/{}'.format(channel)
343
+
344
+ # Set saver object
345
+ saver = IODataBase(path, method=save_method)
346
+
347
+ # Set websocket downloader object
348
+ downloader = DownloadBitfinexData(time_step=time_step, until=until)
349
+ downloader.set_process_data(process_func, **process_params)
350
+ downloader.set_saver(saver, **io_params)
351
+
352
+ downloader(channel, **kwargs)
353
+
354
+ # DEBUG
355
+ # print('TO DEBUG, DATA LEFT:')
356
+ # print(downloader._data)
357
+
358
+
359
+ def get_orders_bitfinex(symbol, precision='P0', frequency='F0', lenght='25',
360
+ time_step=60, until=None, path=None,
361
+ save_method='dataframe', io_params={}):
362
+ """ Download orderbook from Bitfinex exchange. """
363
+ get_data_bitfinex('book_raw', set_orders, time_step=time_step, until=until,
364
+ path=path, save_method=save_method, io_params=io_params,
365
+ symbol=symbol, precision=precision, frequency=frequency,
366
+ lenght=lenght)
367
+
368
+
369
+ def get_orderbook_bitfinex(symbol, precision='P0', frequency='F0', lenght='25',
370
+ time_step=60, until=None, path=None,
371
+ save_method='dataframe', io_params={}):
372
+ """ Download orderbook from Bitfinex exchange. """
373
+ get_data_bitfinex('book', set_marketdepth, time_step=time_step,
374
+ until=until, path=path, save_method=save_method,
375
+ io_params=io_params, symbol=symbol, precision=precision,
376
+ frequency=frequency, lenght=lenght)
377
+
378
+
379
+ def get_trades_bitfinex(symbol, time_step=60, until=None, path=None,
380
+ save_method='dataframe', io_params={}):
381
+ """ Download trades tick by tick from Bitfinex exchange. """
382
+ get_data_bitfinex('trades_raw', set_trades, time_step=time_step,
383
+ until=until, path=path, save_method=save_method,
384
+ io_params=io_params, symbol=symbol)
385
+
386
+
387
+ def get_ohlc_bitfinex(symbol, time_step=60, until=None, path=None,
388
+ save_method='dataframe', io_params={}):
389
+ """ Download trades tick by tick from Bitfinex exchange. """
390
+ get_data_bitfinex('trades', set_ohlc, time_step=time_step, until=until,
391
+ path=path, save_method=save_method, io_params=io_params,
392
+ process_params={'ts': time_step}, symbol=symbol)
393
+
394
+
395
+ # =========================================================================== #
396
+ # Tests #
397
+ # =========================================================================== #
398
+
399
+ # TODO : Clean this part
400
+
401
+ if __name__ == '__main__':
402
+
403
+ import logging.config
404
+
405
+ import yaml
406
+
407
+ logging_path = '/home/arthur/Data/bitfinex_data_bot/scripts/logging.ini'
408
+ with open(logging_path, 'rb') as f:
409
+ config = yaml.safe_load(f.read())
410
+
411
+ logging.config.dictConfig(config)
412
+
413
+ pair = 'tBTCUSD'
414
+ time_step = 60
415
+ until = 900
416
+ path = '/home/arthur/database/bitfinex/'
417
+ save_method = 'dataframe'
418
+ io_params = {'name': '2019'}
419
+
420
+ def f(x):
421
+ return x
422
+
423
+ # get_data_bitfinex('candles', f, symbol=pair, key='trade:1m:tBTCUSD',
424
+ # time_step=time_step, until=until, path=path,
425
+ # save_method=save_method, io_params=io_params)
426
+
427
+ get_orderbook_bitfinex(pair, time_step=time_step, until=until,
428
+ path=path + '/orderbook/' + pair + '/',
429
+ save_method=save_method, io_params=io_params)
430
+
431
+ get_trades_bitfinex(pair, time_step=time_step, until=until,
432
+ path=path + '/trades/' + pair + '/',
433
+ save_method=save_method, io_params=io_params)
434
+
435
+ get_orders_bitfinex(pair, time_step=time_step, until=until,
436
+ path=path + '/orders/' + pair + '/',
437
+ save_method=save_method, io_params=io_params)
438
+
439
+ get_ohlc_bitfinex(pair, time_step=time_step, until=until,
440
+ path=path + '/ohlc/' + pair + '/',
441
+ save_method=save_method, io_params=io_params)