bitunix-automated-crypto-trading 3.1.7__py3-none-any.whl → 3.1.8__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.
@@ -2,10 +2,9 @@ import asyncio
2
2
  import threading
3
3
  from logger import Logger
4
4
  import os
5
- logger = Logger(__name__).get_logger()
6
5
 
7
6
  class AsyncThreadRunner:
8
- def __init__(self, async_func, interval, *args, **kwargs):
7
+ def __init__(self, async_func, logger, interval, *args, **kwargs):
9
8
  self.async_func = async_func
10
9
  self.interval = interval
11
10
  self.args = args
@@ -14,6 +13,7 @@ class AsyncThreadRunner:
14
13
  self._stop_event = threading.Event()
15
14
  self.thread = threading.Thread(target=self.thread_function)
16
15
  self.task = None
16
+ self.logger = logger
17
17
 
18
18
  def thread_function(self):
19
19
  asyncio.set_event_loop(self.loop)
@@ -28,7 +28,7 @@ class AsyncThreadRunner:
28
28
  )
29
29
  self.loop.run_forever()
30
30
  except Exception as e:
31
- logger.info(f"Async Thread function error: {e}, exiting app")
31
+ self.logger.info(f"Async Thread function error: {e}, exiting app")
32
32
  os._exit(1) # Exit the program if the thread is stopped
33
33
  finally:
34
34
  pending = asyncio.all_tasks(self.loop)
@@ -47,10 +47,10 @@ class AsyncThreadRunner:
47
47
  try:
48
48
  await self.async_func(*self.args, **self.kwargs)
49
49
  except Exception as e:
50
- logger.info(f"error in periodic_run async thread {self.thread.name} {e}")
50
+ self.logger.info(f"error in periodic_run async thread {self.thread.name} {e}")
51
51
  os._exit(1) # Exit the program if the thread is stopped
52
52
  await asyncio.sleep(self.interval)
53
- logger.info(f"periodic {self.thread.name} Thread stopped, exiting app.")
53
+ self.logger.info(f"periodic {self.thread.name} Thread stopped, exiting app.")
54
54
  os._exit(1) # Exit the program if the thread is stopped
55
55
  except asyncio.CancelledError:
56
56
  pass
@@ -70,13 +70,13 @@ class AsyncThreadRunner:
70
70
  try:
71
71
  await asyncio.wrap_future(self.task) # Wait for the cancellation to propagate
72
72
  except asyncio.CancelledError:
73
- logger.info(f"{self.thread.name} Task cancelled successfully.")
73
+ self.logger.info(f"{self.thread.name} Task cancelled successfully.")
74
74
  except Exception as e:
75
- logger.error(f"Unexpected error while cancelling the task {self.thread.name}: {e}")
75
+ self.logger.error(f"Unexpected error while cancelling the task {self.thread.name}: {e}")
76
76
 
77
77
  # Stop the event loop safely
78
78
  self.loop.call_soon_threadsafe(self.loop.stop)
79
79
 
80
80
  # Wait for the thread to join
81
81
  self.thread.join()
82
- logger.info(f"{self.thread.name} Thread stopped and event loop cleaned up.")
82
+ self.logger.info(f"{self.thread.name} Thread stopped and event loop cleaned up.")
@@ -9,15 +9,14 @@ from urllib.parse import urlencode
9
9
  from typing import Dict, Any
10
10
  import traceback
11
11
  from logger import Logger
12
- logger = Logger(__name__).get_logger()
13
12
 
14
13
 
15
14
  class BitunixApi:
16
15
 
17
- def __init__(self, api_key, secret_key, settings):
16
+ def __init__(self, api_key, secret_key, settings, logger):
18
17
  self.api_key = api_key
19
18
  self.secret_key = secret_key
20
-
19
+ self.logger = logger
21
20
  self.session = requests.Session()
22
21
  self.session.headers.update({
23
22
  'Content-Type': 'application/json',
@@ -115,7 +114,7 @@ class BitunixApi:
115
114
  headers["sign"] = signature
116
115
 
117
116
  response = self.session.post(endpoint, data=body_string, headers=headers)
118
- logger.info(f"Response: {body_string} {response.json()}")
117
+ self.logger.info(f"Response: {body_string} {response.json()}")
119
118
  response.raise_for_status()
120
119
  return response.json()
121
120
 
@@ -153,28 +152,28 @@ class BitunixApi:
153
152
  if tradeHistory['code']==0:
154
153
  return tradeHistory['data']
155
154
  else:
156
- logger.info(tradeHistory['msg'])
155
+ self.logger.info(tradeHistory['msg'])
157
156
 
158
157
  async def GetPendingOrderData(self,dictparm={}):
159
158
  orders=await self._get_authenticated(self.pending_order_url, dictparm)
160
159
  if orders['code']==0:
161
160
  return orders['data']
162
161
  else:
163
- logger.info(orders['msg'])
162
+ self.logger.info(orders['msg'])
164
163
 
165
164
  async def GetPendingPositionData(self, dictparm={}):
166
165
  positions=await self._get_authenticated(self.pending_positions_URL, dictparm)
167
166
  if positions['code']==0:
168
167
  return positions['data']
169
168
  else:
170
- logger.info(positions['msg'])
169
+ self.logger.info(positions['msg'])
171
170
 
172
171
  async def GetPositionHistoryData(self, dictparm={}):
173
172
  tradeHistory=await self._get_authenticated(self.position_history_Url, dictparm)
174
173
  if tradeHistory['code']==0:
175
174
  return tradeHistory['data']
176
175
  else:
177
- logger.info(tradeHistory['msg'])
176
+ self.logger.info(tradeHistory['msg'])
178
177
 
179
178
 
180
179
  async def GetportfolioData(self):
@@ -182,7 +181,7 @@ class BitunixApi:
182
181
  if portfolio['code']==0:
183
182
  return portfolio['data']
184
183
  else:
185
- logger.info(portfolio['msg'])
184
+ self.logger.info(portfolio['msg'])
186
185
 
187
186
 
188
187
  async def GetTickerslastPrice(self, tickersStr):
@@ -223,7 +222,7 @@ class BitunixApi:
223
222
  except Exception as e:
224
223
  stack = traceback.extract_stack()
225
224
  function_name = stack[-2].name
226
- logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
225
+ self.logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
227
226
 
228
227
  async def GetTickerData(self):
229
228
  try:
@@ -235,7 +234,7 @@ class BitunixApi:
235
234
  except Exception as e:
236
235
  stack = traceback.extract_stack()
237
236
  function_name = stack[-2].name
238
- logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
237
+ self.logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
239
238
 
240
239
  async def GetDepthData(self,symbol,limit):
241
240
  try:
@@ -247,7 +246,7 @@ class BitunixApi:
247
246
  except Exception as e:
248
247
  stack = traceback.extract_stack()
249
248
  function_name = stack[-2].name
250
- logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
249
+ self.logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
251
250
 
252
251
  async def GetKlineHistory(self, ticker, interval, limit, starttime):
253
252
  data = []
@@ -270,7 +269,7 @@ class BitunixApi:
270
269
  except Exception as e:
271
270
  stack = traceback.extract_stack()
272
271
  function_name = stack[-2].name
273
- logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
272
+ self.logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
274
273
 
275
274
  def __del__(self):
276
275
  """Cleanup method to close the session"""
@@ -13,7 +13,6 @@ from AsyncThreadRunner import AsyncThreadRunner
13
13
  from TickerManager import Tickers, Ticker, Interval
14
14
  from DataFrameHtmlRenderer import DataFrameHtmlRenderer
15
15
  from logger import Logger, Colors
16
- logger = Logger(__name__).get_logger()
17
16
  colors = Colors()
18
17
  import gc
19
18
  import os
@@ -27,16 +26,17 @@ import threading
27
26
  cst = pytz.timezone('US/Central')
28
27
 
29
28
  class BitunixSignal:
30
- def __init__(self, api_key, secret_key, settings, threadManager, notifications, bitunixApi):
29
+ def __init__(self, api_key, secret_key, settings, threadManager, notifications, bitunixApi, logger):
31
30
  self.api_key = api_key
32
31
  self.secret_key = secret_key
33
32
  self.settings=settings
34
33
  self.threadManager = threadManager
35
34
  self.notifications = notifications
36
35
  self.bitunixApi = bitunixApi
36
+ self.logger = logger
37
37
 
38
38
  #Ticker object
39
- self.tickerObjects = Tickers(self.settings)
39
+ self.tickerObjects = Tickers(self.settings, self.logger)
40
40
 
41
41
  #these are used for html rendering as well as storing
42
42
  self.signaldf= pd.DataFrame()
@@ -78,8 +78,8 @@ class BitunixSignal:
78
78
  self.bitunixPrivateWebSocketClient = BitunixPrivateWebSocketClient(self.api_key, self.secret_key)
79
79
 
80
80
  if self.settings.USE_PUBLIC_WEBSOCKET:
81
- self.bitunixPublicDepthWebSocketClient = BitunixPublicWebSocketClient(self.api_key, self.secret_key, "depth")
82
- self.bitunixPublicTickerWebSocketClient = BitunixPublicWebSocketClient(self.api_key, self.secret_key, "ticker")
81
+ self.bitunixPublicDepthWebSocketClient = BitunixPublicWebSocketClient(self.api_key, self.secret_key, "depth", logger)
82
+ self.bitunixPublicTickerWebSocketClient = BitunixPublicWebSocketClient(self.api_key, self.secret_key, "ticker", logger)
83
83
 
84
84
  self.tickerList=[]
85
85
 
@@ -129,52 +129,52 @@ class BitunixSignal:
129
129
  await asyncio.create_task(self.DefinehtmlRenderers())
130
130
 
131
131
  #async thread that runs forever jobs
132
- self.GetportfolioDataTask = AsyncThreadRunner(self.GetportfolioData, interval=int(self.settings.PORTFOLIO_API_INTERVAL))
132
+ self.GetportfolioDataTask = AsyncThreadRunner(self.GetportfolioData, self.logger, interval=int(self.settings.PORTFOLIO_API_INTERVAL))
133
133
  self.GetportfolioDataTask.start_thread(thread_name="GetportfolioData")
134
134
 
135
- self.GetPendingPositionDataTask = AsyncThreadRunner(self.GetPendingPositionData, interval=int(self.settings.PENDING_POSITIONS_API_INTERVAL))
135
+ self.GetPendingPositionDataTask = AsyncThreadRunner(self.GetPendingPositionData, self.logger, interval=int(self.settings.PENDING_POSITIONS_API_INTERVAL))
136
136
  self.GetPendingPositionDataTask.start_thread(thread_name="GetPendingPositionData")
137
137
 
138
- self.GetPendingOrderDataTask = AsyncThreadRunner(self.GetPendingOrderData, interval=int(self.settings.PENDING_ORDERS_API_INTERVAL))
138
+ self.GetPendingOrderDataTask = AsyncThreadRunner(self.GetPendingOrderData, self.logger, interval=int(self.settings.PENDING_ORDERS_API_INTERVAL))
139
139
  self.GetPendingOrderDataTask.start_thread(thread_name="GetPendingOrderData")
140
140
 
141
- self.GetTradeHistoryDataTask = AsyncThreadRunner(self.GetTradeHistoryData, interval=int(self.settings.TRADE_HISTORY_API_INTERVAL))
141
+ self.GetTradeHistoryDataTask = AsyncThreadRunner(self.GetTradeHistoryData, self.logger, interval=int(self.settings.TRADE_HISTORY_API_INTERVAL))
142
142
  self.GetTradeHistoryDataTask.start_thread(thread_name="GetTradeHistoryData")
143
143
 
144
- self.GetPositionHistoryDataTask = AsyncThreadRunner(self.GetPositionHistoryData, interval=int(self.settings.POSITION_HISTORY_API_INTERVAL))
144
+ self.GetPositionHistoryDataTask = AsyncThreadRunner(self.GetPositionHistoryData, self.logger, interval=int(self.settings.POSITION_HISTORY_API_INTERVAL))
145
145
  self.GetPositionHistoryDataTask.start_thread(thread_name="GetPositionHistoryData")
146
146
 
147
- self.ProcessPrivateDataTask = AsyncThreadRunner(self.bitunixPrivateWebSocketClient.run_websocket, 0, self.ProcessPrivateData)
147
+ self.ProcessPrivateDataTask = AsyncThreadRunner(self.bitunixPrivateWebSocketClient.run_websocket, self.logger, 0, self.ProcessPrivateData)
148
148
  self.ProcessPrivateDataTask.start_thread(thread_name="ProcessPrivateData")
149
149
 
150
150
  if self.settings.USE_PUBLIC_WEBSOCKET:
151
151
  self.bitunixPublicDepthWebSocketClient.tickerList = self.tickerList
152
- self.StoreDepthDataTask = AsyncThreadRunner(self.bitunixPublicDepthWebSocketClient.run_websocket, 0, self.StoreDepthData)
152
+ self.StoreDepthDataTask = AsyncThreadRunner(self.bitunixPublicDepthWebSocketClient.run_websocket, self.logger, 0, self.StoreDepthData)
153
153
  self.StoreDepthDataTask.start_thread(thread_name="StoreDepthData")
154
154
  self.depth_que = asyncio.Queue()
155
- self.ProcessDepthDataTask = AsyncThreadRunner(self.ProcessDepthData, interval=0) # run only once
155
+ self.ProcessDepthDataTask = AsyncThreadRunner(self.ProcessDepthData, self.logger, interval=0) # run only once
156
156
  self.ProcessDepthDataTask.start_thread(thread_name="ProcessDepthData")
157
157
 
158
158
  self.bitunixPublicTickerWebSocketClient.tickerList = self.tickerList
159
- self.StoreTickerDataTask = AsyncThreadRunner(self.bitunixPublicTickerWebSocketClient.run_websocket, 0, self.StoreTickerData)
159
+ self.StoreTickerDataTask = AsyncThreadRunner(self.bitunixPublicTickerWebSocketClient.run_websocket, self.logger, 0, self.StoreTickerData)
160
160
  self.StoreTickerDataTask.start_thread(thread_name="StoreTickerData")
161
161
  self.ticker_que = asyncio.Queue()
162
- self.ProcessTickerDataTask = AsyncThreadRunner(self.ProcessTickerData, interval=0) # run only once
162
+ self.ProcessTickerDataTask = AsyncThreadRunner(self.ProcessTickerData, self.logger, interval=0) # run only once
163
163
  self.ProcessTickerDataTask.start_thread(thread_name="ProcessTickerData")
164
164
 
165
165
 
166
166
  #normal processes
167
- self.LoadKlineHistoryTask = AsyncThreadRunner(self.LoadKlineHistory, interval=0) # run only once
167
+ self.LoadKlineHistoryTask = AsyncThreadRunner(self.LoadKlineHistory, self.logger, interval=0) # run only once
168
168
  self.LoadKlineHistoryTask.start_thread(thread_name="LoadKlineHistory")
169
169
 
170
- self.AutoTradeProcessTask = AsyncThreadRunner(self.AutoTradeProcess, interval=int(self.settings.SIGNAL_CHECK_INTERVAL))
170
+ self.AutoTradeProcessTask = AsyncThreadRunner(self.AutoTradeProcess, self.logger, interval=int(self.settings.SIGNAL_CHECK_INTERVAL))
171
171
  self.AutoTradeProcessTask.start_thread(thread_name="AutoTradeProcess")
172
172
 
173
- self.checkTickerAndAutotradeStatusTask = AsyncThreadRunner(self.checkTickerAndAutotradeStatus, interval=0)
173
+ self.checkTickerAndAutotradeStatusTask = AsyncThreadRunner(self.checkTickerAndAutotradeStatus, self.logger, interval=0)
174
174
  self.checkTickerAndAutotradeStatusTask.start_thread(thread_name="checkTickerAndAutotradeStatus")
175
175
 
176
176
  if not self.settings.USE_PUBLIC_WEBSOCKET:
177
- self.GetTickerDataTask = AsyncThreadRunner(self.GetTickerData, interval=int(self.settings.TICKER_DATA_API_INTERVAL))
177
+ self.GetTickerDataTask = AsyncThreadRunner(self.GetTickerData, self.logger, interval=int(self.settings.TICKER_DATA_API_INTERVAL))
178
178
  self.GetTickerDataTask.start_thread(thread_name="GetTickerData")
179
179
 
180
180
 
@@ -227,7 +227,7 @@ class BitunixSignal:
227
227
  if data is not None:
228
228
  self.tickerObjects.load_kline_history(ticker, intervalId, self.settings.BARS, data)
229
229
  if self.settings.VERBOSE_LOGGING:
230
- logger.info(f"kline_history: elapsed time {time.time()-start}")
230
+ self.logger.info(f"kline_history: elapsed time {time.time()-start}")
231
231
  self.notifications.add_notification("Kline history loaded")
232
232
 
233
233
  #api data
@@ -258,7 +258,7 @@ class BitunixSignal:
258
258
 
259
259
  self.lastTickerDataTime = time.time()
260
260
  if self.settings.VERBOSE_LOGGING:
261
- logger.info(f"GetTickerData: elapsed time {time.time()-start}")
261
+ self.logger.info(f"GetTickerData: elapsed time {time.time()-start}")
262
262
  if self.settings.BENCHMARK:
263
263
  self.connection = sqlite3.connect("bitunix.db")
264
264
  self.cursor = self.connection.cursor()
@@ -300,10 +300,10 @@ class BitunixSignal:
300
300
  self.tickerObjects.form_candle(self.tuples_list)
301
301
  self.lastTickerDataTime = time.time()
302
302
  except Exception as e:
303
- logger.info(f"Function: ProcessTickerData, {e}, {e.args}, {type(e).__name__}")
304
- logger.info(traceback.print_exc())
303
+ self.logger.info(f"Function: ProcessTickerData, {e}, {e.args}, {type(e).__name__}")
304
+ self.logger.info(traceback.print_exc())
305
305
  await asyncio.sleep(0.01)
306
- logger.info(f"ProcessTickerData: exitied out of the loop, exiting app")
306
+ self.logger.info(f"ProcessTickerData: exitied out of the loop, exiting app")
307
307
  os._exit(1) # Exit the program
308
308
 
309
309
 
@@ -333,10 +333,10 @@ class BitunixSignal:
333
333
  self.depthdf["tickerObj"] = self.depthdf.index.map(self.tickerObjects.get_tickerDict())
334
334
  self.depthdf.apply(self.apply_depth_data2, axis=1)
335
335
  except Exception as e:
336
- logger.info(f"Function: ProcessTickerData, {e}, {e.args}, {type(e).__name__}")
337
- logger.info(traceback.print_exc())
336
+ self.logger.info(f"Function: ProcessTickerData, {e}, {e.args}, {type(e).__name__}")
337
+ self.logger.info(traceback.print_exc())
338
338
  await asyncio.sleep(0.01)
339
- logger.info(f"ProcessDepthData: exitied out of the loop, exiting app")
339
+ self.logger.info(f"ProcessDepthData: exitied out of the loop, exiting app")
340
340
  os._exit(1) # Exit the program
341
341
 
342
342
  def apply_depth_data2(self, row):
@@ -367,9 +367,9 @@ class BitunixSignal:
367
367
  del data, tickerdf, tuples_list
368
368
  gc.collect()
369
369
  except Exception as e:
370
- logger.info(e)
370
+ self.logger.info(e)
371
371
  if self.settings.VERBOSE_LOGGING:
372
- logger.info(f"apply_last_data: elapsed time {time.time()-start}")
372
+ self.logger.info(f"apply_last_data: elapsed time {time.time()-start}")
373
373
 
374
374
  # non websocket method
375
375
  # this is called to update bid and ask,
@@ -411,9 +411,9 @@ class BitunixSignal:
411
411
  self.portfoliodfStyle= self.portfoliodfrenderer.render_html(self.portfoliodf)
412
412
 
413
413
  except Exception as e:
414
- logger.info(f"Function: GetportfolioData, {e}, {e.args}, {type(e).__name__}")
414
+ self.logger.info(f"Function: GetportfolioData, {e}, {e.args}, {type(e).__name__}")
415
415
  if self.settings.VERBOSE_LOGGING:
416
- logger.info(f"GetportfolioData: elapsed time {time.time()-start}")
416
+ self.logger.info(f"GetportfolioData: elapsed time {time.time()-start}")
417
417
 
418
418
  async def GetPendingPositionData(self):
419
419
  start=time.time()
@@ -470,9 +470,9 @@ class BitunixSignal:
470
470
 
471
471
 
472
472
  except Exception as e:
473
- logger.info(f"Function: GetPendingPositionData, {e}, {e.args}, {type(e).__name__}")
473
+ self.logger.info(f"Function: GetPendingPositionData, {e}, {e.args}, {type(e).__name__}")
474
474
  if self.settings.VERBOSE_LOGGING:
475
- logger.info(f"GetPendingPositionData: elapsed time {time.time()-start}")
475
+ self.logger.info(f"GetPendingPositionData: elapsed time {time.time()-start}")
476
476
 
477
477
  async def GetPendingOrderData(self):
478
478
  start=time.time()
@@ -489,9 +489,9 @@ class BitunixSignal:
489
489
  self.orderdfStyle= self.orderdfrenderer.render_html(self.orderdf)
490
490
 
491
491
  except Exception as e:
492
- logger.info(f"Function: GetPendingOrderData, {e}, {e.args}, {type(e).__name__}")
492
+ self.logger.info(f"Function: GetPendingOrderData, {e}, {e.args}, {type(e).__name__}")
493
493
  if self.settings.VERBOSE_LOGGING:
494
- logger.info(f"GetPendingOrderData: elapsed time {time.time()-start}")
494
+ self.logger.info(f"GetPendingOrderData: elapsed time {time.time()-start}")
495
495
 
496
496
  async def GetPositionHistoryData(self):
497
497
  start=time.time()
@@ -509,9 +509,9 @@ class BitunixSignal:
509
509
  self.positionHistorydfStyle= self.positionHistorydfrenderer.render_html(self.positionHistorydf)
510
510
 
511
511
  except Exception as e:
512
- logger.info(f"Function: GetPositionHistoryData, {e}, {e.args}, {type(e).__name__}")
512
+ self.logger.info(f"Function: GetPositionHistoryData, {e}, {e.args}, {type(e).__name__}")
513
513
  if self.settings.VERBOSE_LOGGING:
514
- logger.info(f"GetPositionHistoryData: elapsed time {time.time()-start}")
514
+ self.logger.info(f"GetPositionHistoryData: elapsed time {time.time()-start}")
515
515
 
516
516
  async def GetTradeHistoryData(self):
517
517
  start=time.time()
@@ -526,9 +526,9 @@ class BitunixSignal:
526
526
  # Filter trades for the current symbol and convert them to a list of dicts
527
527
  tickerObj.trades = grouped_trades.get_group(symbol).to_dict("records")
528
528
  except Exception as e:
529
- logger.info(f"Function: GetTradeHistoryData, {e}, {e.args}, {type(e).__name__}")
529
+ self.logger.info(f"Function: GetTradeHistoryData, {e}, {e.args}, {type(e).__name__}")
530
530
  if self.settings.VERBOSE_LOGGING:
531
- logger.info(f"GetTradeHistoryData: elapsed time {time.time()-start}")
531
+ self.logger.info(f"GetTradeHistoryData: elapsed time {time.time()-start}")
532
532
 
533
533
 
534
534
  ###########################################################################################################
@@ -545,6 +545,7 @@ class BitunixSignal:
545
545
  inuseTickers = set(inuse1 + inuse2)
546
546
 
547
547
  # Extract buy/sell ticker data
548
+ self.signaldf_filtered = pd.DataFrame();
548
549
  self.tickerObjects.getCurrentData(period)
549
550
 
550
551
  self.signaldf_full = self.tickerObjects.signaldf_full
@@ -616,14 +617,14 @@ class BitunixSignal:
616
617
  )
617
618
 
618
619
  except Exception as e:
619
- logger.info(f"Function: BuySellList, {e}, {e.args}, {type(e).__name__}")
620
- logger.info(traceback.print_exc())
620
+ self.logger.info(f"Function: BuySellList, {e}, {e.args}, {type(e).__name__}")
621
+ self.logger.info(traceback.print_exc())
621
622
  del inuse1, inuse2, inuseTickers
622
623
  gc.collect()
623
624
 
624
625
  async def AutoTradeProcess(self):
625
626
  if self.settings.VERBOSE_LOGGING:
626
- logger.info(f"AutoTradeProcess started")
627
+ self.logger.info(f"AutoTradeProcess started")
627
628
  start=time.time()
628
629
 
629
630
  period = self.settings.OPTION_MOVING_AVERAGE
@@ -885,6 +886,41 @@ class BitunixSignal:
885
886
  )
886
887
  continue
887
888
 
889
+ # BOS
890
+ if self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_CLOSE:
891
+ if row.side == 'BUY' and self.signaldf_full.at[row.symbol, f'{period}_bos'] == "SELL" and total_pnl>0:
892
+ last, bid, ask, mtv = await self.GetTickerBidLastAsk(row.symbol)
893
+ price = (ask if row['side'] == "BUY" else bid if row['side'] == "SELL" else last) if bid<=last<=ask else last
894
+
895
+ self.notifications.add_notification(
896
+ f'{colors.CYAN} Closing {"long" if side=="BUY" else "short"} position due to {period} bos for {row.symbol} with {row.qty} qty @ {price})'
897
+ )
898
+ datajs = await self.bitunixApi.PlaceOrder(
899
+ positionId=row.positionId,
900
+ ticker=row.symbol,
901
+ qty=row.qty,
902
+ price=price,
903
+ side=row.side,
904
+ tradeSide="CLOSE"
905
+ )
906
+ continue
907
+
908
+ if row.side == 'SELL' and self.signaldf_full.at[row.symbol, f'{period}_bos'] == "BUY" and total_pnl>0:
909
+ last, bid, ask, mtv = await self.GetTickerBidLastAsk(row.symbol)
910
+ price = (ask if row['side'] == "BUY" else bid if row['side'] == "SELL" else last) if bid<=last<=ask else last
911
+ self.notifications.add_notification(
912
+ f'{colors.CYAN} Closing {"long" if side=="BUY" else "short"} position due to {period} bos for {row.symbol} with {row.qty} qty @ {price})'
913
+ )
914
+ datajs = await self.bitunixApi.PlaceOrder(
915
+ positionId=row.positionId,
916
+ ticker=row.symbol,
917
+ qty=row.qty,
918
+ price=price,
919
+ side=row.side,
920
+ tradeSide="CLOSE"
921
+ )
922
+ continue
923
+
888
924
  # TrendLine
889
925
  if self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_CLOSE:
890
926
  if row.side == 'BUY' and self.signaldf_full.at[row.symbol, f'{period}_trendline'] == "SELL" and total_pnl>0:
@@ -996,11 +1032,11 @@ class BitunixSignal:
996
1032
  except Exception as e:
997
1033
  stack = traceback.extract_stack()
998
1034
  function_name = stack[-1].name
999
- logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
1000
- logger.info(traceback.print_exc())
1035
+ self.logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
1036
+ self.logger.info(traceback.print_exc())
1001
1037
 
1002
1038
  if self.settings.VERBOSE_LOGGING:
1003
- logger.info(f"AutoTradeProcess: elapsed time {time.time()-start}")
1039
+ self.logger.info(f"AutoTradeProcess: elapsed time {time.time()-start}")
1004
1040
  if self.settings.BENCHMARK:
1005
1041
  self.connection = sqlite3.connect("bitunix.db")
1006
1042
  self.cursor = self.connection.cursor()
@@ -1066,7 +1102,7 @@ class BitunixSignal:
1066
1102
 
1067
1103
  self.available = data['available']
1068
1104
  self.margin = data['margin']
1069
- # logger.info(feed)
1105
+ # self.logger.info(feed)
1070
1106
 
1071
1107
  elif channel == 'position':
1072
1108
 
@@ -1104,7 +1140,7 @@ class BitunixSignal:
1104
1140
  del feed
1105
1141
  gc.collect()
1106
1142
  except Exception as e:
1107
- logger.info(f"Function: ProcessPrivateData, {e}, {e.args}, {type(e).__name__}")
1143
+ self.logger.info(f"Function: ProcessPrivateData, {e}, {e.args}, {type(e).__name__}")
1108
1144
 
1109
1145
  def color_cells(val, color):
1110
1146
  return f'background-color: {color}' if val else ''
@@ -8,11 +8,10 @@ import string
8
8
  from typing import Callable
9
9
  import threading
10
10
  from logger import Logger
11
- logger = Logger(__name__).get_logger()
12
11
  import gc
13
12
 
14
13
  class BitunixPublicWebSocketClient:
15
- def __init__(self, api_key, secret_key, type):
14
+ def __init__(self, api_key, secret_key, type, logger):
16
15
  self.api_key = api_key
17
16
  self.secret_key = secret_key
18
17
  self.type = type
@@ -22,6 +21,7 @@ class BitunixPublicWebSocketClient:
22
21
  self.loop = asyncio.new_event_loop()
23
22
  self.loop_thread = threading.Thread(target=self.start_loop)
24
23
  self.loop_thread.daemon = True # Ensure the thread closes with the program
24
+ self.logger=logger
25
25
  self.loop_thread.start()
26
26
 
27
27
 
@@ -35,7 +35,7 @@ class BitunixPublicWebSocketClient:
35
35
 
36
36
  # Wait for the thread to finish
37
37
  self.loop_thread.join()
38
- logger.info("Event loop stopped cleanly")
38
+ self.logger.info("Event loop stopped cleanly")
39
39
 
40
40
 
41
41
  async def run_websocket(self, process_func: Callable):
@@ -44,7 +44,7 @@ class BitunixPublicWebSocketClient:
44
44
  try:
45
45
  async with websockets.connect(self.url, ping_interval=None, open_timeout=30) as self.websocket:
46
46
  connect_response = await self.websocket.recv()
47
- logger.info(f"{self.url} {self.type} websocket connect Response: {connect_response}")
47
+ self.logger.info(f"{self.url} {self.type} websocket connect Response: {connect_response}")
48
48
 
49
49
  self.heartbeat_task = asyncio.create_task(self.send_heartbeat(self.websocket))
50
50
 
@@ -81,12 +81,12 @@ class BitunixPublicWebSocketClient:
81
81
  await process_func(message)
82
82
  logger.warning(f"{self.url} {self.type} WebSocket connection closed")
83
83
  except asyncio.CancelledError:
84
- logger.info(f"{self.url} {self.type} WebSocket receive task cancelled")
84
+ self.logger.info(f"{self.url} {self.type} WebSocket receive task cancelled")
85
85
  self.running = False
86
86
  except websockets.exceptions.ConnectionClosedError as e:
87
- logger.info(f"{self.url} {self.type} Websocket: Connection closed: {e}")
87
+ self.logger.info(f"{self.url} {self.type} Websocket: Connection closed: {e}")
88
88
  except Exception as e:
89
- logger.info(f"{self.url} {self.type} Websocket: Unexpected error: {e}")
89
+ self.logger.info(f"{self.url} {self.type} Websocket: Unexpected error: {e}")
90
90
  pass
91
91
  del message, process_func
92
92
  gc.collect()
@@ -97,11 +97,11 @@ class BitunixPublicWebSocketClient:
97
97
  await websocket.send(json.dumps({"op": "ping", "ping": int(time.time())}))
98
98
  await asyncio.sleep(30)
99
99
  except asyncio.CancelledError:
100
- logger.info(f"{self.url} {self.type} WebSocket hearbeat task cancelled")
100
+ self.logger.info(f"{self.url} {self.type} WebSocket hearbeat task cancelled")
101
101
  except websockets.exceptions.ConnectionClosed:
102
- logger.info(f"{self.url} {self.type} WebSocket connection for heartbeat is closed")
102
+ self.logger.info(f"{self.url} {self.type} WebSocket connection for heartbeat is closed")
103
103
  except Exception as e:
104
- logger.info(f"{self.url} {self.type} Websocket for heartbeat: Unexpected error: {e}")
104
+ self.logger.info(f"{self.url} {self.type} Websocket for heartbeat: Unexpected error: {e}")
105
105
  pass
106
106
 
107
107
  async def stop_websocket(self):
@@ -124,7 +124,7 @@ class BitunixPublicWebSocketClient:
124
124
  finally:
125
125
  # Stop the event loop
126
126
  self.loop.call_soon_threadsafe(self.loop.stop)
127
- logger.info(f"{self.url} {self.type} WebSocket thread stopped and resources cleaned up.")
127
+ self.logger.info(f"{self.url} {self.type} WebSocket thread stopped and resources cleaned up.")
128
128
 
129
129
  class BitunixPrivateWebSocketClient:
130
130
  def __init__(self, api_key, secret_key):
@@ -149,7 +149,7 @@ class BitunixPrivateWebSocketClient:
149
149
 
150
150
  # Wait for the thread to finish
151
151
  self.loop_thread.join()
152
- logger.info("Event loop stopped cleanly")
152
+ self.logger.info("Event loop stopped cleanly")
153
153
 
154
154
  async def run_websocket(self, process_func: Callable):
155
155
  self.running = True
@@ -157,7 +157,7 @@ class BitunixPrivateWebSocketClient:
157
157
  try:
158
158
  async with websockets.connect(self.url, ping_interval=None, open_timeout=30) as self.websocket:
159
159
  connect_response = await self.websocket.recv()
160
- logger.info(f"{self.url} websocket connect Response: {connect_response}")
160
+ self.logger.info(f"{self.url} websocket connect Response: {connect_response}")
161
161
 
162
162
  self.heartbeat_task = asyncio.create_task(self.send_heartbeat(self.websocket))
163
163
 
@@ -176,7 +176,7 @@ class BitunixPrivateWebSocketClient:
176
176
  }
177
177
  await self.websocket.send(json.dumps(login_request))
178
178
  login_response = await self.websocket.recv()
179
- logger.info(f"{self.url} Login Response: {login_response}")
179
+ self.logger.info(f"{self.url} Login Response: {login_response}")
180
180
 
181
181
  self.recv_task = asyncio.create_task(self.receive_messages(process_func))
182
182
  await self.recv_task
@@ -195,12 +195,12 @@ class BitunixPrivateWebSocketClient:
195
195
  await process_func(message)
196
196
  logger.warning(f"{self.type} WebSocket connection closed")
197
197
  except asyncio.CancelledError:
198
- logger.info(f"{self.url} WebSocket receive task cancelled")
198
+ self.logger.info(f"{self.url} WebSocket receive task cancelled")
199
199
  self.running = False
200
200
  except websockets.exceptions.ConnectionClosedError as e:
201
- logger.info(f"{self.url} Websocket: Connection closed: {e}")
201
+ self.logger.info(f"{self.url} Websocket: Connection closed: {e}")
202
202
  except Exception as e:
203
- logger.info(f"{self.url} Websocket: Unexpected error: {e}")
203
+ self.logger.info(f"{self.url} Websocket: Unexpected error: {e}")
204
204
  pass
205
205
  del message, process_func
206
206
  gc.collect()
@@ -211,11 +211,11 @@ class BitunixPrivateWebSocketClient:
211
211
  await websocket.send(json.dumps({"op": "ping", "ping": int(time.time())}))
212
212
  await asyncio.sleep(30)
213
213
  except asyncio.CancelledError:
214
- logger.info(f"{self.url} WebSocket hearbeat task cancelled")
214
+ self.logger.info(f"{self.url} WebSocket hearbeat task cancelled")
215
215
  except websockets.exceptions.ConnectionClosed:
216
- logger.info(f"{self.url} WebSocket connection for heartbeat is closed")
216
+ self.logger.info(f"{self.url} WebSocket connection for heartbeat is closed")
217
217
  except Exception as e:
218
- logger.info(f"{self.url} Websocket for heartbeat: Unexpected error: {e}")
218
+ self.logger.info(f"{self.url} Websocket for heartbeat: Unexpected error: {e}")
219
219
  pass
220
220
 
221
221
  async def stop_websocket(self):
@@ -238,7 +238,7 @@ class BitunixPrivateWebSocketClient:
238
238
  finally:
239
239
  # Stop the event loop
240
240
  self.loop.call_soon_threadsafe(self.loop.stop)
241
- logger.info(f"{self.url} WebSocket thread stopped and resources cleaned up.")
241
+ self.logger.info(f"{self.url} WebSocket thread stopped and resources cleaned up.")
242
242
 
243
243
 
244
244
  async def generate_signature(self, api_key, secret_key, nonce):
@@ -1,19 +1,19 @@
1
1
  from datetime import datetime
2
2
  import pytz
3
3
  from logger import Logger
4
- logger = Logger(__name__).get_logger()
5
4
 
6
5
  class NotificationManager:
7
- def __init__(self, max_size=100):
6
+ def __init__(self, logger, max_size=100):
8
7
  self.max_size = max_size
9
8
  self.notifications = []
9
+ self.logger = logger
10
10
 
11
11
  def add_notification(self, notification):
12
12
  # Add the new notification at the top
13
13
  timezone = pytz.timezone('America/Chicago')
14
14
  timestamp = datetime.now(timezone).strftime('%Y-%m-%d %H:%M:%S')
15
15
  self.notifications.insert(0, f'({timestamp}) {notification}')
16
- logger.info(f'({timestamp}) {notification}')
16
+ self.logger.info(f'({timestamp}) {notification}')
17
17
  # Ensure the list doesn't exceed the maximum size
18
18
  if len(self.notifications) > self.max_size:
19
19
  self.notifications.pop()