mm-toolbox 0.1.0__tar.gz

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.
Files changed (38) hide show
  1. mm_toolbox-0.1.0/LICENSE +21 -0
  2. mm_toolbox-0.1.0/PKG-INFO +123 -0
  3. mm_toolbox-0.1.0/README.md +90 -0
  4. mm_toolbox-0.1.0/mm_toolbox/__init__.py +11 -0
  5. mm_toolbox-0.1.0/mm_toolbox/src/__init__.py +23 -0
  6. mm_toolbox-0.1.0/mm_toolbox/src/candles/__init__.py +3 -0
  7. mm_toolbox-0.1.0/mm_toolbox/src/candles/base.py +400 -0
  8. mm_toolbox-0.1.0/mm_toolbox/src/candles/tick.py +41 -0
  9. mm_toolbox-0.1.0/mm_toolbox/src/candles/time.py +43 -0
  10. mm_toolbox-0.1.0/mm_toolbox/src/candles/volume.py +54 -0
  11. mm_toolbox-0.1.0/mm_toolbox/src/logging/__init__.py +1 -0
  12. mm_toolbox-0.1.0/mm_toolbox/src/logging/discord.py +97 -0
  13. mm_toolbox-0.1.0/mm_toolbox/src/logging/logger.py +128 -0
  14. mm_toolbox-0.1.0/mm_toolbox/src/logging/telegram.py +105 -0
  15. mm_toolbox-0.1.0/mm_toolbox/src/moving_average/__init__.py +2 -0
  16. mm_toolbox-0.1.0/mm_toolbox/src/moving_average/ema.py +108 -0
  17. mm_toolbox-0.1.0/mm_toolbox/src/moving_average/hma.py +92 -0
  18. mm_toolbox-0.1.0/mm_toolbox/src/numba/__init__.py +39 -0
  19. mm_toolbox-0.1.0/mm_toolbox/src/numba/array.py +182 -0
  20. mm_toolbox-0.1.0/mm_toolbox/src/numba/linalg.py +47 -0
  21. mm_toolbox-0.1.0/mm_toolbox/src/orderbook/__init__.py +18 -0
  22. mm_toolbox-0.1.0/mm_toolbox/src/orderbook/hft.py +751 -0
  23. mm_toolbox-0.1.0/mm_toolbox/src/orderbook/standard.py +345 -0
  24. mm_toolbox-0.1.0/mm_toolbox/src/ringbuffer/__init__.py +3 -0
  25. mm_toolbox-0.1.0/mm_toolbox/src/ringbuffer/multidim.py +201 -0
  26. mm_toolbox-0.1.0/mm_toolbox/src/ringbuffer/onedim.py +341 -0
  27. mm_toolbox-0.1.0/mm_toolbox/src/ringbuffer/twodim.py +349 -0
  28. mm_toolbox-0.1.0/mm_toolbox/src/rounding/__init__.py +1 -0
  29. mm_toolbox-0.1.0/mm_toolbox/src/rounding/rounding.py +130 -0
  30. mm_toolbox-0.1.0/mm_toolbox/src/time/__init__.py +8 -0
  31. mm_toolbox-0.1.0/mm_toolbox/src/time/time.py +79 -0
  32. mm_toolbox-0.1.0/mm_toolbox/src/websocket/__init__.py +1 -0
  33. mm_toolbox-0.1.0/mm_toolbox/src/websocket/stream.py +448 -0
  34. mm_toolbox-0.1.0/mm_toolbox/src/websocket/tools.py +93 -0
  35. mm_toolbox-0.1.0/mm_toolbox/src/weights/__init__.py +2 -0
  36. mm_toolbox-0.1.0/mm_toolbox/src/weights/ema.py +27 -0
  37. mm_toolbox-0.1.0/mm_toolbox/src/weights/geometric.py +27 -0
  38. mm_toolbox-0.1.0/pyproject.toml +46 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 beatzxbt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,123 @@
1
+ Metadata-Version: 2.1
2
+ Name: mm-toolbox
3
+ Version: 0.1.0
4
+ Summary: "high-performance python tools for market making strategies."
5
+ Home-page: https://github.com/beatzxbt/mm-toolbox
6
+ License: MIT
7
+ Keywords: market making,high performance python,orderbook
8
+ Author: beatzxbt
9
+ Author-email: 121855680+beatzxbt@users.noreply.github.com
10
+ Requires-Python: >=3.10.0,<3.13
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Natural Language :: English
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: Implementation :: CPython
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
24
+ Requires-Dist: aiohttp (>=3.10.4,<4.0.0)
25
+ Requires-Dist: aiosonic (>=0.21.0,<0.22.0)
26
+ Requires-Dist: ciso8601 (>=2.3.1,<3.0.0)
27
+ Requires-Dist: numba (>=0.60.0,<0.61.0)
28
+ Requires-Dist: numpy (>=2.1.0,<3.0.0)
29
+ Requires-Dist: orjson (>=3.10.7,<4.0.0)
30
+ Requires-Dist: scipy (>=1.14.0,<2.0.0)
31
+ Project-URL: Repository, https://github.com/beatzxbt/mm-toolbox
32
+ Description-Content-Type: text/markdown
33
+
34
+ # MM Toolbox
35
+
36
+ **MM Toolbox** is a Python library designed to provide high-performance tools for market making strategies.
37
+
38
+ ## Contents
39
+
40
+ ```plaintext
41
+ mm-toolbox/
42
+ ├── mm_toolbox/
43
+ │ ├── src/
44
+ │ │ ├── candles/ # Tools for handling and aggregating candlestick data
45
+ │ │ ├── logging/ # Lightweight logging utilities
46
+ │ │ ├── moving_average/ # Implementations of various moving averages
47
+ │ │ ├── numba/ # Numba-optimized functions and utilities
48
+ │ │ ├── orderbook/ # Multiple orderbook implementations & tools
49
+ │ │ ├── ringbuffer/ # Efficient fixed-size circular buffers
50
+ │ │ ├── rounding/ # Utilities for rounding prices and sizes
51
+ │ │ ├── time/ # High-performance time utilities
52
+ │ │ ├── websocket/ # WebSocket handling utilities
53
+ │ │ ├── weights/ # Weight generators
54
+ │ ├── __init__.py # Package initialization
55
+ ├── tests/ # Unit tests for all the modules
56
+ ├── .gitignore # Git ignore file
57
+ ├── LICENSE # License information
58
+ ├── README.md # Main documentation file
59
+ ├── requirements.txt # Python dependencies
60
+ └── setup.py # Setup script for pip installation
61
+ ```
62
+
63
+ ## Installation
64
+
65
+ MM Toolbox is available on PyPI and can be installed using pip:
66
+
67
+ ```bash
68
+ pip install mm_toolbox
69
+ ```
70
+
71
+ To install directly from the source, clone the repository and install the dependencies:
72
+ ```bash
73
+ git clone https://github.com/beatzxbt/mm-toolbox.git
74
+ cd mm-toolbox
75
+ pip install -r requirements.txt
76
+ python setup.py install
77
+ ```
78
+
79
+ ## Usage
80
+
81
+ After installation, you can start using MM Toolbox by importing the necessary modules:
82
+ ```python
83
+ from mm_toolbox.src.orderbook import Orderbook
84
+ from mm_toolbox.src.moving_average import ExponentialMovingAverage
85
+ from mm_toolbox.src.time import time_iso8601
86
+
87
+ # Example usage:
88
+ ob = Orderbook(size=100)
89
+ ```
90
+
91
+ ## Planned additions/upgrades
92
+
93
+ ### v0.2.0
94
+ **Numba**: Complete coverage of [Numba's top-level functions](https://numba.readthedocs.io/en/stable/reference/numpysupported.html#other-functions) (with custom implementation if faster).
95
+
96
+ **Orderbook**: Directly update BBA, Imbalance Feature, ++Performance
97
+
98
+ **Candles**: ++Performance
99
+
100
+ **Websocket**: Fast websocket pool + auto swapping latency mechanism.
101
+
102
+ ### v0.3.0
103
+ **Candles**: Multi-trigger candle (time/tick/volume).
104
+
105
+ **Logger**: High performance logger w/Database support integrated.
106
+
107
+ **Moving Average**: Weighted Moving Average (WMA).
108
+
109
+ ### v0.4.0
110
+ **Orderbook**: [HFT Orderbook](/mm_toolbox/src/orderbook/hft.py), aiming to be fastest Python orderbook on GitHub.
111
+
112
+ ## License
113
+
114
+ MM Toolbox is licensed under the MIT License. See the [LICENSE](/LICENSE) file for more information.
115
+
116
+ ## Contributing
117
+
118
+ Contributions are welcome! Please read the [CONTRIBUTING.md](/CONTRIBUTING.md) for guidelines on how to contribute to this project.
119
+
120
+ ## Contact
121
+
122
+ For questions or support, please open an [issue](https://github.com/beatzxbt/mm-toolbox/issues).
123
+ I can also be reached on [Twitter](https://twitter.com/BeatzXBT) and [Discord](@gamingbeatz) :D
@@ -0,0 +1,90 @@
1
+ # MM Toolbox
2
+
3
+ **MM Toolbox** is a Python library designed to provide high-performance tools for market making strategies.
4
+
5
+ ## Contents
6
+
7
+ ```plaintext
8
+ mm-toolbox/
9
+ ├── mm_toolbox/
10
+ │ ├── src/
11
+ │ │ ├── candles/ # Tools for handling and aggregating candlestick data
12
+ │ │ ├── logging/ # Lightweight logging utilities
13
+ │ │ ├── moving_average/ # Implementations of various moving averages
14
+ │ │ ├── numba/ # Numba-optimized functions and utilities
15
+ │ │ ├── orderbook/ # Multiple orderbook implementations & tools
16
+ │ │ ├── ringbuffer/ # Efficient fixed-size circular buffers
17
+ │ │ ├── rounding/ # Utilities for rounding prices and sizes
18
+ │ │ ├── time/ # High-performance time utilities
19
+ │ │ ├── websocket/ # WebSocket handling utilities
20
+ │ │ ├── weights/ # Weight generators
21
+ │ ├── __init__.py # Package initialization
22
+ ├── tests/ # Unit tests for all the modules
23
+ ├── .gitignore # Git ignore file
24
+ ├── LICENSE # License information
25
+ ├── README.md # Main documentation file
26
+ ├── requirements.txt # Python dependencies
27
+ └── setup.py # Setup script for pip installation
28
+ ```
29
+
30
+ ## Installation
31
+
32
+ MM Toolbox is available on PyPI and can be installed using pip:
33
+
34
+ ```bash
35
+ pip install mm_toolbox
36
+ ```
37
+
38
+ To install directly from the source, clone the repository and install the dependencies:
39
+ ```bash
40
+ git clone https://github.com/beatzxbt/mm-toolbox.git
41
+ cd mm-toolbox
42
+ pip install -r requirements.txt
43
+ python setup.py install
44
+ ```
45
+
46
+ ## Usage
47
+
48
+ After installation, you can start using MM Toolbox by importing the necessary modules:
49
+ ```python
50
+ from mm_toolbox.src.orderbook import Orderbook
51
+ from mm_toolbox.src.moving_average import ExponentialMovingAverage
52
+ from mm_toolbox.src.time import time_iso8601
53
+
54
+ # Example usage:
55
+ ob = Orderbook(size=100)
56
+ ```
57
+
58
+ ## Planned additions/upgrades
59
+
60
+ ### v0.2.0
61
+ **Numba**: Complete coverage of [Numba's top-level functions](https://numba.readthedocs.io/en/stable/reference/numpysupported.html#other-functions) (with custom implementation if faster).
62
+
63
+ **Orderbook**: Directly update BBA, Imbalance Feature, ++Performance
64
+
65
+ **Candles**: ++Performance
66
+
67
+ **Websocket**: Fast websocket pool + auto swapping latency mechanism.
68
+
69
+ ### v0.3.0
70
+ **Candles**: Multi-trigger candle (time/tick/volume).
71
+
72
+ **Logger**: High performance logger w/Database support integrated.
73
+
74
+ **Moving Average**: Weighted Moving Average (WMA).
75
+
76
+ ### v0.4.0
77
+ **Orderbook**: [HFT Orderbook](/mm_toolbox/src/orderbook/hft.py), aiming to be fastest Python orderbook on GitHub.
78
+
79
+ ## License
80
+
81
+ MM Toolbox is licensed under the MIT License. See the [LICENSE](/LICENSE) file for more information.
82
+
83
+ ## Contributing
84
+
85
+ Contributions are welcome! Please read the [CONTRIBUTING.md](/CONTRIBUTING.md) for guidelines on how to contribute to this project.
86
+
87
+ ## Contact
88
+
89
+ For questions or support, please open an [issue](https://github.com/beatzxbt/mm-toolbox/issues).
90
+ I can also be reached on [Twitter](https://twitter.com/BeatzXBT) and [Discord](@gamingbeatz) :D
@@ -0,0 +1,11 @@
1
+ # Re-export all sub scripts for fast access.
2
+ from .src.candles import *
3
+ from .src.logging import *
4
+ from .src.moving_average import *
5
+ from .src.numba import *
6
+ from .src.orderbook import *
7
+ from .src.ringbuffer import *
8
+ from .src.rounding import *
9
+ from .src.time import *
10
+ from .src.websocket import *
11
+ from .src.weights import *
@@ -0,0 +1,23 @@
1
+ __VERSION__ = "0.1.0"
2
+
3
+ def clean_repo(repo_name: str) -> None:
4
+ """Clean the repository"""
5
+ import os
6
+
7
+ if os.name == "nt":
8
+ command = f"rmdir build /s /q & rmdir /s /q {repo_name}.egg-info & rmdir /s /q dist"
9
+ elif os.name == "posix":
10
+ command = f"rm -r build & rm -r {repo_name}.egg-info & rm -r dist"
11
+ else:
12
+ command = ""
13
+
14
+ os.system(command)
15
+
16
+ def install_package(package: str):
17
+ """Install desired package"""
18
+ import pip
19
+
20
+ if hasattr(pip, 'main'):
21
+ pip.main(['install', package])
22
+ else:
23
+ pip._internal.main(['install', package])
@@ -0,0 +1,3 @@
1
+ from .tick import TickCandles
2
+ from .volume import VolumeCandles
3
+ from .time import TimeCandles
@@ -0,0 +1,400 @@
1
+ import numpy as np
2
+ from abc import ABC, abstractmethod
3
+ from typing import Tuple, Iterator, Union
4
+
5
+ from mm_toolbox.src.ringbuffer import RingBufferMultiDim
6
+
7
+
8
+ class BaseCandles(ABC):
9
+ """
10
+ A class to aggregate trades into pre-defined fixed buckets.
11
+
12
+ Format
13
+ ---------
14
+ Candle[]:
15
+ [0] = Open Price
16
+ [1] = High Price
17
+ [2] = Low Price
18
+ [3] = Close Price
19
+ [4] = Buy Volume
20
+ [5] = Sell Volume
21
+ [6] = VWAP Price
22
+ [7] = Total Trades
23
+ [8] = Open Timestamp
24
+ [9] = Close Timestamp
25
+
26
+ Parameters
27
+ ----------
28
+ num_candles : int
29
+ The number of candles to maintain in the ring buffer
30
+ """
31
+ def __init__(self, num_candles: int) -> None:
32
+ self.num_candles = num_candles
33
+
34
+ self.open_price = 0.0
35
+ self.high_price = -np.inf
36
+ self.low_price = np.inf
37
+ self.close_price = 0.0
38
+ self.buy_volume = 0.0
39
+ self.sell_volume = 0.0
40
+ self.vwap_price = 0.0
41
+ self.total_trades = 0.0
42
+ self.open_timestamp = 0.0
43
+ self.close_timestamp = 0.0
44
+
45
+ self._cum_price_volume_ = 0.0
46
+ self._total_volume_ = 0.0
47
+
48
+ self.ringbuffer = RingBufferMultiDim(
49
+ shape=(num_candles, 10),
50
+ dtype=np.float64
51
+ )
52
+
53
+ def as_array(self) -> np.ndarray[np.ndarray]:
54
+ """
55
+ Returns the aggregated candle data as a NumPy array.
56
+
57
+ Returns
58
+ -------
59
+ np.ndarray[np.ndarray]
60
+ The array of aggregated candle data.
61
+ """
62
+ if not self.ringbuffer.is_empty:
63
+ if self.open_timestamp != 0.0:
64
+ return np.concatenate((
65
+ self.ringbuffer.as_array(),
66
+ np.array([[
67
+ self.open_price,
68
+ self.high_price,
69
+ self.low_price,
70
+ self.close_price,
71
+ self.buy_volume,
72
+ self.sell_volume,
73
+ self.vwap_price,
74
+ self.total_trades,
75
+ self.open_timestamp,
76
+ self.close_timestamp
77
+ ]])
78
+ ))
79
+
80
+ else:
81
+ return self.ringbuffer.as_array()
82
+
83
+ else:
84
+ return np.array([[]], dtype=np.float64)
85
+
86
+ def reset_current_candle(self) -> None:
87
+ """
88
+ Resets the current candle data to its initial state.
89
+ """
90
+ self.open_price = 0.0
91
+ self.high_price = -np.inf
92
+ self.low_price = np.inf
93
+ self.close_price = 0.0
94
+ self.buy_volume = 0.0
95
+ self.sell_volume = 0.0
96
+ self.vwap_price = 0.0
97
+ self.total_trades = 0.0
98
+ self.open_timestamp = 0.0
99
+ self.close_timestamp = 0.0
100
+ self.total_volume = 0.0
101
+
102
+ self._cum_price_volume_ = 0.0
103
+ self._total_volume_ = 0.0
104
+
105
+ def insert_candle(
106
+ self,
107
+ open_price: float,
108
+ high_price: float,
109
+ low_price: float,
110
+ close_price: float,
111
+ buy_volume: float,
112
+ sell_volume: float,
113
+ vwap_price: float,
114
+ total_trades: float,
115
+ open_timestamp: float,
116
+ close_timestamp: float
117
+ ) -> None:
118
+ """
119
+ Inserts a completed candle into the ring buffer and resets the current candle.
120
+
121
+ Parameters
122
+ ----------
123
+ open_price : float
124
+ The open price of the candle.
125
+
126
+ high_price : float
127
+ The high price of the candle.
128
+
129
+ low_price : float
130
+ The low price of the candle.
131
+
132
+ close_price : float
133
+ The close price of the candle.
134
+
135
+ buy_volume : float
136
+ The buy volume of the candle.
137
+
138
+ sell_volume : float
139
+ The sell volume of the candle.
140
+
141
+ vwap_price : float
142
+ The volume-weighted average price of the candle.
143
+
144
+ total_trades : float
145
+ The total number of trades in the candle.
146
+
147
+ open_timestamp : float
148
+ The open timestamp of the candle.
149
+
150
+ close_timestamp : float
151
+ The close timestamp of the candle.
152
+ """
153
+ current_candle = np.array([
154
+ open_price,
155
+ high_price,
156
+ low_price,
157
+ close_price,
158
+ buy_volume,
159
+ sell_volume,
160
+ vwap_price,
161
+ total_trades,
162
+ open_timestamp,
163
+ close_timestamp
164
+ ])
165
+ self.ringbuffer.append(current_candle)
166
+ self.reset_current_candle()
167
+
168
+ @abstractmethod
169
+ def process_trade(self, timestamp: float, side: bool, price: float, size: float) -> None:
170
+ """
171
+ Processes a single trade tick and updates the current candle data.
172
+
173
+ Parameters
174
+ ----------
175
+ timestamp : float
176
+ The timestamp of the trade.
177
+
178
+ side : bool
179
+ Whether the trade is a buy (True) or sell (False).
180
+
181
+ price : float
182
+ The price at which the trade occurred.
183
+
184
+ size : float
185
+ The size (volume) of the trade.
186
+ """
187
+ pass
188
+
189
+ def initialize(self, trades: np.ndarray) -> None:
190
+ """
191
+ Initializes the candle data with a batch of trades.
192
+
193
+ Parameters
194
+ ----------
195
+ trades : np.ndarray
196
+ A 2D NumPy array of trades in the format [[Timestamp, Side, Price, Size]].
197
+ """
198
+ for trade in trades:
199
+ self.process_trade(*trade)
200
+
201
+ def update(self, timestamp: float, side: bool, price: float, size: float) -> None:
202
+ """
203
+ Updates the candle data with a new trade. Checks if the update is
204
+ as a result of stale data being recieved or not.
205
+
206
+ Parameters
207
+ ----------
208
+ timestamp : float
209
+ The timestamp of the trade.
210
+
211
+ side : bool
212
+ Whether the trade is a buy (True) or sell (False).
213
+
214
+ price : float
215
+ The price at which the trade occurred.
216
+
217
+ size : float
218
+ The size (volume) of the trade.
219
+ """
220
+ if timestamp >= self.open_timestamp:
221
+ self.process_trade(timestamp, side, price, size)
222
+
223
+ def calculate_vwap(self, price: float, size: float) -> float:
224
+ self._cum_price_volume_ += price * size
225
+ self._total_volume_ += size
226
+ return self._cum_price_volume_ / self._total_volume_
227
+
228
+ def durations(self) -> np.ndarray[float]:
229
+ candles = self.as_array()
230
+ return candles[:, 9] - candles[:, 8]
231
+
232
+ def imbalances(self) -> np.ndarray[float]:
233
+ candles = self.as_array()
234
+ return candles[:, 4] / candles[:, 5]
235
+
236
+ def average_true_range(self) -> np.ndarray[float]:
237
+ """
238
+ Calculate the true range of a trading price bar.
239
+
240
+ The true range is the greatest of the following:
241
+ - The difference between the current high and the current low,
242
+ - The absolute difference between the current high and the previous close,
243
+ - The absolute difference between the current low and the previous close.
244
+
245
+ Returns
246
+ -------
247
+ np.ndarray[float]
248
+ The true range of price in the candles.
249
+ """
250
+ candles = self.as_array()
251
+
252
+ if len(candles) < 2:
253
+ return np.array([], dtype=np.float64)
254
+
255
+ high_low_diff = candles[:, 1] - candles[:, 2]
256
+ high_prev_close_diff = np.abs(candles[1:, 1] - candles[:-1, 3])
257
+ low_prev_close_diff = np.abs(candles[1:, 2] - candles[:-1, 3])
258
+
259
+ # True Range is the maximum of the three calculated differences
260
+ true_range = np.maximum.reduce([
261
+ high_low_diff[1:],
262
+ high_prev_close_diff,
263
+ low_prev_close_diff
264
+ ])
265
+
266
+ return true_range
267
+
268
+ def rsi(self, period: int = 14) -> np.ndarray[float]:
269
+ """
270
+ Calculate the Relative Strength Index (RSI) for the given period.
271
+
272
+ Parameters
273
+ ----------
274
+ period : int
275
+ The period over which to calculate the RSI (default is 14).
276
+
277
+ Returns
278
+ -------
279
+ np.ndarray
280
+ The RSI values for each candle.
281
+ """
282
+ close_prices = self.close_prices
283
+
284
+ if period >= close_prices.size:
285
+ raise RuntimeWarning(f"Not enough candles for period {period}, calculating partial RSI only.")
286
+
287
+ delta = np.diff(close_prices, 1)
288
+ gain = np.where(delta > 0.0, delta, 0.0)
289
+ loss = np.where(delta < 0.0, -delta, 0.0)
290
+
291
+ avg_gain = np.zeros_like(close_prices)
292
+ avg_loss = np.zeros_like(close_prices)
293
+
294
+ for i in range(1, period):
295
+ # Partial RSI is just previous price's SMA
296
+ avg_gain[i] = gain[:i].mean()
297
+ avg_loss[i] = loss[:i].mean()
298
+
299
+ for i in range(period, len(close_prices) - 1):
300
+ avg_gain[i] = (avg_gain[i - 1] * (period - 1.0) + gain[i]) / period
301
+ avg_loss[i] = (avg_loss[i - 1] * (period - 1.0) + loss[i]) / period
302
+
303
+ rs = np.divide(avg_gain[1:], avg_loss[1:], where=avg_loss[1:] != 0)
304
+ rsi = 100.0 - (100.0 / (1.0 + rs))
305
+
306
+ return rsi
307
+
308
+ def bollinger_bands(self, period: int = 20, num_std_dev: float = 2.0) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
309
+ """
310
+ Calculate Bollinger Bands (BB) for the given period.
311
+
312
+ Parameters
313
+ ----------
314
+ period : int
315
+ The period over which to calculate the Bollinger Bands (default is 20).
316
+
317
+ num_std_dev : float
318
+ The number of standard deviations to use for the bands (default is 2.0).
319
+
320
+ Returns
321
+ -------
322
+ Tuple[np.ndarray, np.ndarray, np.ndarray]
323
+ The lower band, middle band (SMA), and upper band.
324
+ """
325
+ close_prices = self.as_array()[:, 3]
326
+
327
+ sma = np.convolve(close_prices, np.ones(period) / period, mode='valid')
328
+ rolling_std = np.zeros_like(sma)
329
+
330
+ for i in range(sma.size):
331
+ rolling_std[i] = np.std(close_prices[i:i + period])
332
+
333
+ upper_band = sma + num_std_dev * rolling_std
334
+ lower_band = sma - num_std_dev * rolling_std
335
+
336
+ return lower_band, sma, upper_band
337
+
338
+ @property
339
+ def current_candle(self) -> np.ndarray[float]:
340
+ return np.array([
341
+ self.open_price,
342
+ self.high_price,
343
+ self.low_price,
344
+ self.close_price,
345
+ self.buy_volume,
346
+ self.sell_volume,
347
+ self.vwap_price,
348
+ self.total_trades,
349
+ self.open_timestamp,
350
+ self.close_timestamp
351
+ ])
352
+
353
+ @property
354
+ def open_prices(self) -> np.ndarray[float]:
355
+ if not self.ringbuffer.is_empty:
356
+ return self.as_array()[:, 0]
357
+
358
+ @property
359
+ def high_prices(self) -> np.ndarray[float]:
360
+ if not self.ringbuffer.is_empty:
361
+ return self.as_array()[:, 1]
362
+
363
+ @property
364
+ def low_prices(self) -> np.ndarray[float]:
365
+ if not self.ringbuffer.is_empty:
366
+ return self.as_array()[:, 2]
367
+
368
+ @property
369
+ def close_prices(self) -> np.ndarray[float]:
370
+ if not self.ringbuffer.is_empty:
371
+ return self.as_array()[:, 3]
372
+
373
+ @property
374
+ def buy_volumes(self) -> np.ndarray[float]:
375
+ if not self.ringbuffer.is_empty:
376
+ return self.as_array()[:, 4]
377
+
378
+ @property
379
+ def sell_volumes(self) -> np.ndarray[float]:
380
+ if not self.ringbuffer.is_empty:
381
+ return self.as_array()[:, 5]
382
+
383
+ @property
384
+ def vwap_prices(self) -> np.ndarray[float]:
385
+ if not self.ringbuffer.is_empty:
386
+ return self.as_array()[:, 6]
387
+
388
+ @property
389
+ def all_trades(self) -> np.ndarray[float]:
390
+ if not self.ringbuffer.is_empty:
391
+ return self.as_array()[:, 7]
392
+
393
+ def __getitem__(self, index: Union[int, Tuple]) -> np.ndarray:
394
+ return self.as_array()[index]
395
+
396
+ def __len__(self) -> int:
397
+ return len(self.ringbuffer)
398
+
399
+ def __iter__(self) -> Iterator[np.ndarray]:
400
+ return iter(self.as_array())