bitunix-automated-crypto-trading 3.1.7__tar.gz → 3.1.8__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 (24) hide show
  1. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/PKG-INFO +1 -1
  2. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/README.md +16 -4
  3. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/AsyncThreadRunner.py +8 -8
  4. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/BitunixApi.py +12 -13
  5. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/BitunixSignal.py +83 -47
  6. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/BitunixWebSocket.py +21 -21
  7. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/NotificationManager.py +3 -3
  8. bitunix_automated_crypto_trading-3.1.8/bitunix_automated_crypto_trading/SupportResistance.py +117 -0
  9. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/ThreadManager.py +4 -3
  10. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/TickerManager.py +56 -47
  11. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/bitunix.py +42 -16
  12. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/config.py +8 -2
  13. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/logger.py +1 -1
  14. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading.egg-info/PKG-INFO +1 -1
  15. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/setup.py +1 -1
  16. bitunix_automated_crypto_trading-3.1.7/bitunix_automated_crypto_trading/SupportResistance.py +0 -89
  17. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/DataFrameHtmlRenderer.py +0 -0
  18. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading/__init__.py +0 -0
  19. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading.egg-info/SOURCES.txt +0 -0
  20. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading.egg-info/dependency_links.txt +0 -0
  21. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading.egg-info/entry_points.txt +0 -0
  22. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading.egg-info/requires.txt +0 -0
  23. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/bitunix_automated_crypto_trading.egg-info/top_level.txt +0 -0
  24. {bitunix_automated_crypto_trading-3.1.7 → bitunix_automated_crypto_trading-3.1.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bitunix_automated_crypto_trading
3
- Version: 3.1.7
3
+ Version: 3.1.8
4
4
  Summary: Bitunix Futures Auto Trading Platform
5
5
  Home-page: https://github.com/tcj2001/bitunix-automated-crypto-trading
6
6
  Author: tcj2001
@@ -2,6 +2,8 @@
2
2
 
3
3
  A real-time cryptocurrency trading platform built with FastAPI and WebSocket technology using Bitunix API and websockets for Futures. The platform provides automated trading capabilities, real-time market data visualization, and portfolio management features.
4
4
 
5
+ Supports running the app in multiple instances (bots) with each instance having its own configuration file and env file containing the API keys and other parameters.
6
+
5
7
  ## Features
6
8
  - Real-time private account/new postion/new order data streaming via WebSocket
7
9
  - Real-time public depth/kline for bid, ask and last streaming via WebSocket or thru api calls, configurable in the config file
@@ -61,7 +63,6 @@ The platform can be configured through the `config.py` file or `config.txt`. Key
61
63
  - `BARS`: Number of bars to use for study and charting
62
64
 
63
65
  - `Technical Indicators Parameters`:
64
- - `BOS_PERIOD`: Break of structure period, number of bars to look back to determine the previous high or low
65
66
  - `MA_FAST`: Fast moving average period
66
67
  - `MA_MEDIUM`: Medium moving average period
67
68
  - `MA_SLOW`: Slow moving average period
@@ -75,7 +76,6 @@ The platform can be configured through the `config.py` file or `config.txt`. Key
75
76
  - `ADX_PERIOD`: ADX period
76
77
 
77
78
  - `Study Parameters`:
78
- - `BOS_STUDY`: Enable Break Of Structure study
79
79
  - `EMA_STUDY`: Enable EMA study
80
80
  - `EMA_CHART`: Display EMA chart
81
81
  - `EMA_STUDY`: Enable EMA study
@@ -102,6 +102,12 @@ The platform can be configured through the `config.py` file or `config.txt`. Key
102
102
  - `RSI_CHECK_ON_OPEN`: Check RSI on open
103
103
  - `RSI_CHECK_ON_CLOSE`: Check RSI on close
104
104
 
105
+ - `BOS_PERIOD`: Break of structure period, number of bars to look back to determine the previous high or low
106
+ - `BOS_STUDY`: Enable Break Of Structure study
107
+ - `BOS_CHART`: Display Break Of Structure chart
108
+ - `BOS_CHECK_ON_OPEN`: Check bos support and resistance on open
109
+ - `BOS_CHECK_ON_CLOSE`: Check bos support and resistance on close
110
+
105
111
  - `TRENDLINE_PEAK_DISTANCE` : distance between peaks or troughs
106
112
  - `TRENDLINE_STUDY`: Enable Trendline support and resistance study
107
113
  - `TRENDLINE_CHART`: Display Trendline chart
@@ -162,6 +168,7 @@ The platform can be configured through the `config.py` file or `config.txt`. Key
162
168
  - Take Profit amount
163
169
  - Accept Loss amount
164
170
  - BOS study is basically when the price breakout from the previous high or low
171
+ - Trendline study is basically when the price breakout from the trendline support or resistance
165
172
  - You can control the study like Moving Average, MACD, Bollinger Band, RSI or close proximity to high or low of the candle using the env file
166
173
  - You can control the trading strategy using the CalculateStudy function in TickerManager.py and AutoTradeProcess function in BitunixSignal.py
167
174
  - Changes are activated by unchecking and checking the AutoTrade checkbox
@@ -193,7 +200,7 @@ The platform can be configured through the `config.py` file or `config.txt`. Key
193
200
  apt-get install -y python3-pip wget unzip dos2unix && \
194
201
  python3 -m pip install --upgrade pip && \
195
202
  mkdir bitunix && cd bitunix && \
196
- wget https://github.com/tcj2001/bitunix-automated-crypto-trading/archive/refs/tags/2.0.tar.gz -O bitunix.tar.gz && \
203
+ wget https://github.com/tcj2001/bitunix-automated-crypto-trading/archive/refs/tags/v3.1.8.tar.gz -O bitunix.tar.gz && \
197
204
  mkdir code && \
198
205
  tar --strip-components=1 -xvzf bitunix.tar.gz -C code && \
199
206
  cd code && \
@@ -201,7 +208,12 @@ The platform can be configured through the `config.py` file or `config.txt`. Key
201
208
  cp sampleenv.txt .env"
202
209
  - The package will be installed in the bitunix/code directory
203
210
  - cd bitunix/code
204
- - python3 bitunix.py
211
+ - python3 bitunix.py .env config.txt 8000 (This is the default even if you dont pass these)
212
+
213
+ For multiple instance or bots
214
+ - python3 bitunix.py .env1 bot1.txt 8001
215
+ - python3 bitunix.py .env2 bot2.txt 8002
216
+
205
217
 
206
218
  - Windows
207
219
  - mkdir c:\bitunix
@@ -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 ''