bitunix-automated-crypto-trading 3.3.9__tar.gz → 3.4.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.
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/PKG-INFO +1 -1
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/AsyncThreadRunner.py +2 -2
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/BitunixSignal.py +90 -84
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/TickerManager.py +12 -8
- bitunix_automated_crypto_trading-3.4.0/bitunix_automated_crypto_trading/version.py +1 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading.egg-info/PKG-INFO +1 -1
- bitunix_automated_crypto_trading-3.3.9/bitunix_automated_crypto_trading/version.py +0 -1
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/README.md +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/BitunixApi.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/BitunixWebSocket.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/DataFrameHtmlRenderer.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/NotificationManager.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/SupportResistance.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/__init__.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/bitunix.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/config.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading/logger.py +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading.egg-info/SOURCES.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading.egg-info/dependency_links.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading.egg-info/entry_points.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading.egg-info/requires.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/bitunix_automated_crypto_trading.egg-info/top_level.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/setup.cfg +0 -0
- {bitunix_automated_crypto_trading-3.3.9 → bitunix_automated_crypto_trading-3.4.0}/setup.py +0 -0
@@ -87,8 +87,8 @@ class AsyncThreadRunner:
|
|
87
87
|
# For now, we'll just log and continue, allowing the manager to detect if the thread dies from other reasons.
|
88
88
|
|
89
89
|
# Check stop event again before sleeping to allow immediate stopping
|
90
|
-
if self._stop_event.is_set():
|
91
|
-
|
90
|
+
#if self._stop_event.is_set():
|
91
|
+
# break
|
92
92
|
|
93
93
|
# Use asyncio.sleep to allow graceful cancellation
|
94
94
|
try:
|
@@ -158,14 +158,14 @@ class BitunixSignal:
|
|
158
158
|
self.StoreDepthDataTask = AsyncThreadRunner(self.bitunixPublicDepthWebSocketClient.run_websocket, self.logger, 0, self.StoreDepthData)
|
159
159
|
self.StoreDepthDataTask.start_thread(thread_name="StoreDepthData")
|
160
160
|
self.depth_que = asyncio.Queue()
|
161
|
-
self.ProcessDepthDataTask = AsyncThreadRunner(self.ProcessDepthData, self.logger, interval=
|
161
|
+
self.ProcessDepthDataTask = AsyncThreadRunner(self.ProcessDepthData, self.logger, interval=int(self.settings.TICKER_DATA_API_INTERVAL)) # run only once
|
162
162
|
self.ProcessDepthDataTask.start_thread(thread_name="ProcessDepthData")
|
163
163
|
|
164
164
|
self.bitunixPublicTickerWebSocketClient.tickerList = self.tickerList
|
165
165
|
self.StoreTickerDataTask = AsyncThreadRunner(self.bitunixPublicTickerWebSocketClient.run_websocket, self.logger, 0, self.StoreTickerData)
|
166
166
|
self.StoreTickerDataTask.start_thread(thread_name="StoreTickerData")
|
167
167
|
self.ticker_que = asyncio.Queue()
|
168
|
-
self.ProcessTickerDataTask = AsyncThreadRunner(self.ProcessTickerData, self.logger, interval=
|
168
|
+
self.ProcessTickerDataTask = AsyncThreadRunner(self.ProcessTickerData, self.logger, interval=int(self.settings.TICKER_DATA_API_INTERVAL)) # run only once
|
169
169
|
self.ProcessTickerDataTask.start_thread(thread_name="ProcessTickerData")
|
170
170
|
|
171
171
|
|
@@ -238,38 +238,39 @@ class BitunixSignal:
|
|
238
238
|
|
239
239
|
#api data
|
240
240
|
async def GetTickerData(self):
|
241
|
-
if
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
241
|
+
if self.settings.VERBOSE_LOGGING:
|
242
|
+
self.logger.info(f"GetTickerData started")
|
243
|
+
start=time.time()
|
244
|
+
# Get the current time and set the seconds and microseconds to zero
|
245
|
+
current_time = datetime.now()
|
246
|
+
current_minute = current_time.replace(second=0, microsecond=0)
|
247
|
+
ts = int(current_minute.timestamp())*1000
|
248
|
+
|
249
|
+
#api used insted of websocket
|
250
|
+
data = await self.bitunixApi.GetTickerData()
|
251
|
+
self.tickerdf = pd.DataFrame()
|
252
|
+
if data:
|
253
|
+
|
254
|
+
# Create a DataFrame from the data
|
255
|
+
self.tickerdf = pd.DataFrame(data, columns=["symbol", "last"])
|
256
|
+
|
257
|
+
#remove not required symbols
|
258
|
+
self.tickerdf.loc[~self.tickerdf['symbol'].isin(self.tickerObjects.symbols()), :] = None
|
259
|
+
self.tickerdf.dropna(inplace=True)
|
260
|
+
|
261
|
+
self.tickerdf['ts']=ts
|
262
|
+
self.tickerdf["tickerObj"] = self.tickerdf["symbol"].map(self.tickerObjects.get_tickerDict())
|
263
|
+
self.tuples_list = list(zip(self.tickerdf["tickerObj"], self.tickerdf["last"].astype(float), self.tickerdf["ts"]))
|
264
|
+
self.tickerObjects.form_candle(self.tuples_list)
|
264
265
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
266
|
+
self.lastTickerDataTime = time.time()
|
267
|
+
if self.settings.VERBOSE_LOGGING:
|
268
|
+
self.logger.info(f"GetTickerData: elapsed time {time.time()-start}")
|
269
|
+
if self.settings.BENCHMARK:
|
270
|
+
self.connection = sqlite3.connect(self.settings.DATABASE)
|
271
|
+
self.cursor = self.connection.cursor()
|
272
|
+
self.cursor.execute("INSERT INTO benchmark (process_name, time) VALUES (?, ?)", ("GetTickerData", time.time()-start))
|
273
|
+
self.connection.commit()
|
273
274
|
|
274
275
|
async def drain_queue(self, queue):
|
275
276
|
items = []
|
@@ -285,32 +286,34 @@ class BitunixSignal:
|
|
285
286
|
|
286
287
|
# Function to process the last price deque
|
287
288
|
async def ProcessTickerData(self):
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
self.
|
310
|
-
self.
|
311
|
-
|
312
|
-
|
313
|
-
|
289
|
+
if self.settings.VERBOSE_LOGGING:
|
290
|
+
self.logger.info(f"Started ProcessTickerData")
|
291
|
+
start=time.time()
|
292
|
+
try:
|
293
|
+
# Get the current time and set the seconds and microseconds to zero
|
294
|
+
latest_data = {}
|
295
|
+
reversed_items = await self.drain_queue(self.ticker_que)
|
296
|
+
while reversed_items:
|
297
|
+
message = reversed_items.popleft()
|
298
|
+
data = json.loads(message)
|
299
|
+
if data.get('symbol') and data.get('ch') == 'ticker':
|
300
|
+
symbol = data["symbol"]
|
301
|
+
ts = data["ts"]
|
302
|
+
if symbol not in latest_data or ts > latest_data[symbol]['ts']:
|
303
|
+
latest_data[symbol] = {'ts': ts, 'last': float(data['data']['la'])}
|
304
|
+
await asyncio.sleep(0.01)
|
305
|
+
# Convert to DataFrame
|
306
|
+
self.tickerdf = pd.DataFrame.from_dict(latest_data, orient="index")
|
307
|
+
if not self.tickerdf.empty:
|
308
|
+
self.tickerdf["tickerObj"] = self.tickerdf.index.map(self.tickerObjects.get_tickerDict())
|
309
|
+
self.tuples_list = list(zip(self.tickerdf["tickerObj"], self.tickerdf["last"].astype(float), self.tickerdf["ts"]))
|
310
|
+
self.tickerObjects.form_candle(self.tuples_list)
|
311
|
+
self.lastTickerDataTime = time.time()
|
312
|
+
except Exception as e:
|
313
|
+
self.logger.info(f"Function: ProcessTickerData, {e}, {e.args}, {type(e).__name__}")
|
314
|
+
self.logger.info(traceback.print_exc())
|
315
|
+
if self.settings.VERBOSE_LOGGING:
|
316
|
+
self.logger.info(f"ProcessTickerData: elapsed time {time.time()-start}")
|
314
317
|
|
315
318
|
|
316
319
|
#websocket data to update bid and ask
|
@@ -320,30 +323,31 @@ class BitunixSignal:
|
|
320
323
|
|
321
324
|
# Function to process the bid, ask
|
322
325
|
async def ProcessDepthData(self):
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
self.
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
326
|
+
if self.settings.VERBOSE_LOGGING:
|
327
|
+
self.logger.info(f"Started ProcessDepthData")
|
328
|
+
start=time.time()
|
329
|
+
try:
|
330
|
+
latest_data = {}
|
331
|
+
reversed_items = await self.drain_queue(self.depth_que)
|
332
|
+
while reversed_items:
|
333
|
+
message = reversed_items.popleft()
|
334
|
+
data = json.loads(message)
|
335
|
+
if data.get('symbol') and data.get('ch') == 'depth_book1':
|
336
|
+
symbol = data["symbol"]
|
337
|
+
ts = data["ts"]
|
338
|
+
if symbol not in latest_data or ts > latest_data[symbol]['ts']:
|
339
|
+
latest_data[symbol] = {'ts': ts, 'bid': float(data['data']['b'][0][0]), 'ask': float(data['data']['a'][0][0])}
|
340
|
+
await asyncio.sleep(0.01)
|
341
|
+
# Convert to DataFrame
|
342
|
+
self.depthdf = pd.DataFrame.from_dict(latest_data, orient="index")
|
343
|
+
if not self.depthdf.empty:
|
344
|
+
self.depthdf["tickerObj"] = self.depthdf.index.map(self.tickerObjects.get_tickerDict())
|
345
|
+
self.depthdf.apply(self.apply_depth_data2, axis=1)
|
346
|
+
except Exception as e:
|
347
|
+
self.logger.info(f"Function: ProcessTickerData, {e}, {e.args}, {type(e).__name__}")
|
348
|
+
self.logger.info(traceback.print_exc())
|
349
|
+
if self.settings.VERBOSE_LOGGING:
|
350
|
+
self.logger.info(f"ProcessDepthData: elapsed time {time.time()-start}")
|
347
351
|
|
348
352
|
def apply_depth_data2(self, row):
|
349
353
|
row["tickerObj"].set_ask(row["ask"])
|
@@ -930,6 +934,8 @@ class BitunixSignal:
|
|
930
934
|
if price > sl_midpoint and side == "BUY" or price < sl_midpoint and side == "SELL":
|
931
935
|
if breakeven_calc:
|
932
936
|
slPrice = price * (1 - float(self.settings.PROFIT_PERCENTAGE) /100 /self.settings.LEVERAGE) if side == "BUY" else price * (1 + float(self.settings.PROFIT_PERCENTAGE) / 100 / self.settings.LEVERAGE)
|
937
|
+
if slPrice < avgOpenPrice and side == "BUY" or slPrice > avgOpenPrice and side == "SELL":
|
938
|
+
slPrice = avgOpenPrice
|
933
939
|
else:
|
934
940
|
slPrice = price * (1 - float(self.settings.LOSS_PERCENTAGE) / 100 / self.settings.LEVERAGE) if side == "BUY" else price * (1 + float(self.settings.LOSS_PERCENTAGE) / 100 / self.settings.LEVERAGE)
|
935
941
|
slPrice = Decimal(await self.str_precision(slPrice))
|
@@ -944,7 +950,7 @@ class BitunixSignal:
|
|
944
950
|
datajs3 = await self.bitunixApi.ModifyTpSlOrder({'orderId':slorderId,'slPrice':str(slPrice),'slQty':str(qty),'slStopType':slStopType,'slOrderType':slOrderType})
|
945
951
|
if datajs3 is not None:
|
946
952
|
self.notifications.add_notification(
|
947
|
-
f'{colors.CYAN} Stop Loss order for {row.symbol} moved from {old_slPrice} to
|
953
|
+
f'{colors.CYAN} Stop Loss order for {row.symbol} moved from {old_slPrice} to {"profitable" if breakeven_calc else ""} {slPrice}'
|
948
954
|
)
|
949
955
|
|
950
956
|
|
@@ -330,8 +330,9 @@ class Interval:
|
|
330
330
|
|
331
331
|
buy_conditions = ema_open or macd_open or bbm_open or rsi_open or bos_open or trendline_open
|
332
332
|
additional_buy_conditions = (
|
333
|
-
(
|
334
|
-
|
333
|
+
(self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN and self.adx_signal == "STRONG") if self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN else True
|
334
|
+
) and (
|
335
|
+
(self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN and self.candle_trend == "BULLISH") if self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN else True
|
335
336
|
)
|
336
337
|
|
337
338
|
|
@@ -345,8 +346,9 @@ class Interval:
|
|
345
346
|
|
346
347
|
sell_conditions = ema_close or macd_close or bbm_close or rsi_close or bos_close or trendline_close
|
347
348
|
additional_sell_conditions = (
|
348
|
-
(self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN and self.adx_signal == "STRONG") and
|
349
|
-
|
349
|
+
(self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN and self.adx_signal == "STRONG") if self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN else True
|
350
|
+
) and (
|
351
|
+
(self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN and self.candle_trend == "BEARISH") if self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN else True
|
350
352
|
)
|
351
353
|
|
352
354
|
# Determine current signal
|
@@ -372,8 +374,9 @@ class Interval:
|
|
372
374
|
|
373
375
|
buy_conditions = ema_open and macd_open and bbm_open and rsi_open and bos_open and trendline_open
|
374
376
|
additional_buy_conditions = (
|
375
|
-
(
|
376
|
-
|
377
|
+
(self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN and self.adx_signal == "STRONG") if self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN else True
|
378
|
+
) and (
|
379
|
+
(self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN and self.candle_trend == "BULLISH") if self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN else True
|
377
380
|
)
|
378
381
|
|
379
382
|
# Check for SELL signal
|
@@ -392,8 +395,9 @@ class Interval:
|
|
392
395
|
|
393
396
|
sell_conditions = ema_close and macd_close and bbm_close and rsi_close and bos_close and trendline_close
|
394
397
|
additional_sell_conditions = (
|
395
|
-
(self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN and self.adx_signal == "STRONG")
|
396
|
-
|
398
|
+
(self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN and self.adx_signal == "STRONG") if self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN else True
|
399
|
+
) and (
|
400
|
+
(self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN and self.candle_trend == "BEARISH") if self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN else True
|
397
401
|
)
|
398
402
|
|
399
403
|
# Determine current signal
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "3.4.0"
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "3.3.9"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|