bitunix-automated-crypto-trading 3.3.2__py3-none-any.whl → 3.3.5__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.
@@ -4,6 +4,7 @@ import time
4
4
  import json
5
5
  import hashlib
6
6
  import asyncio
7
+ import re
7
8
  import requests
8
9
  from urllib.parse import urlencode
9
10
  from typing import Dict, Any
@@ -33,17 +34,19 @@ class BitunixApi:
33
34
  self.depth_Url='https://fapi.bitunix.com/api/v1/futures/market/depth'
34
35
  self.placeOrder_Url="https://fapi.bitunix.com/api/v1/futures/trade/place_order"
35
36
  self.flashClose_Url="https://fapi.bitunix.com/api/v1/futures/trade/flash_close_position"
37
+ self.get_order_url="https://fapi.bitunix.com/api/v1/futures/trade/get_order_detail"
36
38
  self.pending_order_url="https://fapi.bitunix.com/api/v1/futures/trade/get_pending_orders"
37
39
  self.cancelOrder_Url="https://fapi.bitunix.com/api/v1/futures/trade/cancel_orders"
40
+ self.pending_tpsl_order_url="https://fapi.bitunix.com/api/v1/futures/tpsl/get_pending_orders"
41
+ self.place_tpsl_order_url="https://fapi.bitunix.com/api/v1/futures/tpsl/place_order"
42
+ self.modify_tpsl_order_url="https://fapi.bitunix.com/api/v1/futures/tpsl/modify_order"
43
+ self.cancel_tpsl_Order_Url="https://fapi.bitunix.com/api/v1/futures/tpsl/cancel_order"
38
44
  self.Trade_history_Url="https://fapi.bitunix.com/api/v1/futures/trade/get_history_trades"
39
45
  self.position_history_Url="https://fapi.bitunix.com/api/v1/futures/position/get_history_positions"
40
46
 
41
47
  async def update_settings(self, settings):
42
48
  self.settings = settings
43
49
 
44
- async def create_timestamp(self):
45
- return str(int(time.time()*1000))
46
-
47
50
  async def is_near_high_of_day(self, current_value, high_of_day, threshold_percentage=5):
48
51
  # Calculate the difference as a percentage of the high of the day
49
52
  difference_percentage = ((high_of_day - current_value) / high_of_day) * 100
@@ -56,70 +59,80 @@ class BitunixApi:
56
59
  # Check if the difference is within the threshold
57
60
  return difference_percentage <= threshold_percentage
58
61
 
62
+ #signature generation related methods
63
+ async def _create_timestamp(self):
64
+ return str(int(time.time()*1000))
59
65
 
60
66
  async def _generate_nonce(self) -> str:
61
67
  random_bytes = secrets.token_bytes(32)
62
68
  return base64.b64encode(random_bytes).decode('utf-8')
63
69
 
70
+ async def _generate_sign_api(self, nonce, timestamp, api_key, secret_key, method, data):
71
+ query_params = ""
72
+ body = ""
73
+ if data:
74
+ if method.lower() == "get":
75
+ data = {k: v for k, v in data.items() if v is not None}
76
+ query_params = '&'.join([f"{k}={v}" for k, v in sorted(data.items())])
77
+ query_params = re.sub(r'[^a-zA-Z0-9]', '', query_params)
78
+ if method.lower() == "post":
79
+ # body = str(data).replace(" ", "")
80
+ body = str(data)
64
81
 
65
- async def sign_request(self, nonce: str, timestamp: str,
66
- query_params: str = None,
67
- body: str = None) -> str:
68
- query_string = query_params if query_params else ""
69
- body_string = body if body else ""
70
- message = f"{nonce}{timestamp}{self.api_key}{query_string}{body_string}"
71
-
72
- # First SHA256 encryption
73
- digest = hashlib.sha256(message.encode()).hexdigest()
74
-
75
- # Second SHA256 encryption
76
- sign = hashlib.sha256((digest + self.secret_key).encode()).hexdigest()
77
-
78
- return sign
79
-
80
- async def _get(self, endpoint: str, params: Dict[str, Any] = None) -> Dict[str, Any]:
81
- response = self.session.get(endpoint, params=params)
82
- response.raise_for_status()
83
- return response.json()
82
+ digest_input = nonce + timestamp + api_key + query_params + body
83
+ # print(f"digest_input={digest_input}")
84
+ digest = hashlib.sha256((digest_input).encode()).hexdigest()
85
+ # print(f"digest={digest}")
86
+ sign_input = digest + secret_key
87
+ # print(f"sign_input={sign_input}")
88
+ sign = hashlib.sha256((sign_input).encode()).hexdigest()
84
89
 
90
+ return sign
91
+
85
92
  async def _get_authenticated(self, endpoint: str, params: Dict[str, Any] = None) -> Dict[str, Any]:
86
- timestamp = await self.create_timestamp()
93
+ timestamp = await self._create_timestamp()
87
94
  nonce = await self._generate_nonce()
88
95
 
96
+ signature = await self._generate_sign_api(nonce, timestamp, self.api_key, self.secret_key, "get", params)
97
+
89
98
  headers = {
90
99
  "api-key": self.api_key,
100
+ "nonce": nonce,
91
101
  "timestamp": timestamp,
92
- "nonce": nonce,
102
+ "sign": signature, # Placeholder for signature
103
+ "language": "en-US",
104
+ "Content-Type": "application/json"
93
105
  }
94
-
95
- query_string = urlencode(sorted(params.items())).replace('=','').replace('&','') if params else ""
96
- signature = await self.sign_request(nonce, timestamp, query_params=query_string)
97
- headers["sign"] = signature
98
106
 
99
107
  response = self.session.get(endpoint, params=params, headers=headers)
100
108
  response.raise_for_status()
101
109
  return response.json()
102
110
 
103
111
  async def _post_authenticated(self, endpoint: str, data: Dict[str, Any]) -> Dict[str, Any]:
104
- timestamp = await self.create_timestamp()
112
+ timestamp = await self._create_timestamp()
105
113
  nonce = await self._generate_nonce()
106
114
 
115
+ body_string = json.dumps(data, separators=(',',':'))
116
+ signature = await self._generate_sign_api(nonce, timestamp, self.api_key, self.secret_key, "post", body_string)
117
+
107
118
  headers = {
108
119
  "api-key": self.api_key,
109
120
  "timestamp": timestamp,
110
121
  "nonce": nonce,
122
+ "sign": signature,
111
123
  "Content-Type": "application/json"
112
124
  }
113
-
114
- body_string = json.dumps(data, separators=(',', ':'))
115
- signature = await self.sign_request(nonce, timestamp, body=body_string)
116
- headers["sign"] = signature
117
125
 
118
126
  response = self.session.post(endpoint, data=body_string, headers=headers)
119
127
  self.logger.info(f"Response: {body_string} {response.json()}")
120
128
  response.raise_for_status()
121
129
  return response.json()
122
130
 
131
+ async def _get(self, endpoint: str, params: Dict[str, Any] = None) -> Dict[str, Any]:
132
+ response = self.session.get(endpoint, params=params)
133
+ response.raise_for_status()
134
+ return response.json()
135
+
123
136
  async def PlaceOrder(self, ticker, qty, price, side, positionId=0, tradeSide="OPEN",reduceOnly=False, tpPrice=0, tpOrderPrice=0, slPrice=0, slOrderPrice=0):
124
137
  datajs = None
125
138
  if tpPrice == 0 and slPrice == 0:
@@ -143,8 +156,8 @@ class BitunixApi:
143
156
  "symbol": ticker,
144
157
  "tradeSide":tradeSide,
145
158
  "slPrice": slPrice,
146
- "slStopType": self.settings.STOP_LOSS_PRICE_TYPE,
147
- "slOrderType": self.settings.STOP_LOSS_ORDER_TYPE,
159
+ "slStopType": self.settings.SL_STOP_TYPE,
160
+ "slOrderType": self.settings.SL_ORDER_TYPE,
148
161
  "slOrderPrice": slOrderPrice,
149
162
  "positionId":positionId
150
163
  }
@@ -158,8 +171,8 @@ class BitunixApi:
158
171
  "symbol": ticker,
159
172
  "tradeSide":tradeSide,
160
173
  "tpPrice": tpPrice,
161
- "tpStopType": self.settings.TAKE_PROFIT_PRICE_TYPE,
162
- "tpOrderType": self.settings.TAKE_PROFIT_ORDER_TYPE,
174
+ "tpStopType": self.settings.TP_STOP_TYPE,
175
+ "tpOrderType": self.settings.TP_ORDER_TYPE,
163
176
  "tpOrderPrice":tpOrderPrice,
164
177
  "positionId":positionId
165
178
  }
@@ -173,12 +186,12 @@ class BitunixApi:
173
186
  "symbol": ticker,
174
187
  "tradeSide":tradeSide,
175
188
  "tpPrice": tpPrice,
176
- "tpStopType": self.settings.TAKE_PROFIT_PRICE_TYPE,
177
- "tpOrderType": self.settings.TAKE_PROFIT_ORDER_TYPE,
189
+ "tpStopType": self.settings.TP_STOP_TYPE,
190
+ "tpOrderType": self.settings.TP_ORDER_TYPE,
178
191
  "tpOrderPrice":tpOrderPrice,
179
192
  "slPrice": slPrice,
180
- "slStopType": self.settings.STOP_LOSS_PRICE_TYPE,
181
- "slOrderType": self.settings.STOP_LOSS_ORDER_TYPE,
193
+ "slStopType": self.settings.SL_STOP_TYPE,
194
+ "slOrderType": self.settings.SL_ORDER_TYPE,
182
195
  "slOrderPrice": slOrderPrice,
183
196
  "positionId":positionId
184
197
  }
@@ -201,13 +214,20 @@ class BitunixApi:
201
214
  datajs = await self._post_authenticated(self.cancelOrder_Url,data)
202
215
  return datajs
203
216
 
204
- async def GetTradeHistoryData(self):
205
- tradeHistory=await self._get_authenticated(self.Trade_history_Url)
217
+ async def GetTradeHistoryData(self, dictparm={}):
218
+ tradeHistory=await self._get_authenticated(self.Trade_history_Url, dictparm)
206
219
  if tradeHistory['code']==0:
207
220
  return tradeHistory['data']
208
221
  else:
209
222
  self.logger.info(tradeHistory['msg'])
210
223
 
224
+ async def GetOrderData(self, dictparm={}):
225
+ orders=await self._get_authenticated(self.get_order_url, dictparm)
226
+ if orders['code']==0:
227
+ return orders['data']
228
+ else:
229
+ self.logger.info(orders['msg'])
230
+
211
231
  async def GetPendingOrderData(self,dictparm={}):
212
232
  orders=await self._get_authenticated(self.pending_order_url, dictparm)
213
233
  if orders['code']==0:
@@ -215,6 +235,35 @@ class BitunixApi:
215
235
  else:
216
236
  self.logger.info(orders['msg'])
217
237
 
238
+ async def GetPendingTpSlOrderData(self,dictparm={}):
239
+ orders=await self._get_authenticated(self.pending_tpsl_order_url, dictparm)
240
+ if orders['code']==0:
241
+ return orders['data']
242
+ else:
243
+ self.logger.info(orders['msg'])
244
+
245
+ async def PlaceTpSlOrder(self,dictparm={}):
246
+ orders=await self._post_authenticated(self.place_tpsl_order_url, dictparm)
247
+ if orders['code']==0:
248
+ return orders['data']
249
+ else:
250
+ self.logger.info(orders['msg'])
251
+
252
+ async def ModifyTpSlOrder(self,dictparm={}):
253
+ orders=await self._post_authenticated(self.modify_tpsl_order_url, dictparm)
254
+ if orders['code']==0:
255
+ return orders['data']
256
+ else:
257
+ self.logger.info(orders['msg'])
258
+
259
+ async def CancelTpSlOrder(self, symbol, orderId):
260
+ data = {
261
+ "symbol": symbol,
262
+ "orderId":orderId
263
+ }
264
+ datajs = await self._post_authenticated(self.cancel_tpsl_Order_Url,data)
265
+ return datajs
266
+
218
267
  async def GetPendingPositionData(self, dictparm={}):
219
268
  positions=await self._get_authenticated(self.pending_positions_URL, dictparm)
220
269
  if positions['code']==0:
@@ -646,6 +646,7 @@ class BitunixSignal:
646
646
  async def get_duration_minutes_unixtime(self, trade_time_unix):
647
647
  """Calculates the duration in minutes from trade time to current time."""
648
648
  current_time_unix = int(time.time()) # Get current Unix timestamp
649
+ print(f"Current time (Unix): {current_time_unix}, Trade time (Unix): {trade_time_unix}")
649
650
  duration_seconds = current_time_unix - trade_time_unix
650
651
  duration_minutes = duration_seconds / 60 # Convert seconds to minutes
651
652
  return round(duration_minutes)
@@ -678,6 +679,12 @@ class BitunixSignal:
678
679
  increment = Decimal(f'1e-{decimal_places}')
679
680
  return float(value + increment)
680
681
 
682
+ async def decrement_by_last_decimal(self, value_str):
683
+ value = Decimal(value_str)
684
+ # Count number of decimal places
685
+ decimal_places = abs(value.as_tuple().exponent)
686
+ decrement = Decimal(f'1e-{decimal_places}')
687
+ return float(value - decrement)
681
688
 
682
689
  async def calculate_candles(self, timeframe, duration_minutes):
683
690
 
@@ -752,12 +759,12 @@ class BitunixSignal:
752
759
  tpPrice = price + float(self.settings.PROFIT_AMOUNT)/qty if side == "BUY" else price - float(self.settings.PROFIT_AMOUNT)/qty
753
760
  tpPrice = Decimal(await self.str_precision(tpPrice))
754
761
  tpPrice =float(str(tpPrice.quantize(Decimal(f'1e-{decimal_places}'))))
755
- tpOrderPrice = await self.increment_by_last_decimal(str(tpPrice))
762
+ tpOrderPrice = await self.decrement_by_last_decimal(str(tpPrice))
756
763
  if self.settings.PROFIT_PERCENTAGE > 0 or self.settings.PROFIT_AMOUNT > 0:
757
764
  tpPrice = 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)
758
765
  tpPrice = Decimal(await self.str_precision(tpPrice))
759
766
  tpPrice = float(str(tpPrice.quantize(Decimal(f'1e-{decimal_places}'))))
760
- tpOrderPrice = await self.increment_by_last_decimal(await self.str_precision(tpPrice))
767
+ tpOrderPrice = await self.decrement_by_last_decimal(await self.str_precision(tpPrice))
761
768
 
762
769
  slPrice=0
763
770
  slOrderPrice=0
@@ -777,7 +784,7 @@ class BitunixSignal:
777
784
  f'{colors.YELLOW} Opening {"long" if side=="BUY" else "short"} position for {row.symbol} with {qty} qty @ {price})'
778
785
  )
779
786
  datajs = None
780
- if self.settings.BOT_TAKE_PROFIT_STOP_LOSS:
787
+ if self.settings.BOT_CONTROLS_TP_SL:
781
788
  datajs = await self.bitunixApi.PlaceOrder(row.symbol, qty, price, side)
782
789
  else:
783
790
  if tpPrice == 0 and slPrice == 0:
@@ -838,7 +845,75 @@ class BitunixSignal:
838
845
  select = False
839
846
 
840
847
  if select and int(self.settings.MAX_AUTO_TRADES)!=0:
841
- if self.settings.BOT_TAKE_PROFIT_STOP_LOSS:
848
+
849
+ if self.settings.BOT_TRAIL_TP_SL and self.settings.PROFIT_PERCENTAGE > 0 and self.settings.LOSS_PERCENTAGE > 0:
850
+ last, bid, ask, mtv = await self.GetTickerBidLastAsk(row.symbol)
851
+ price = (bid if side == "BUY" else ask if side == "SELL" else last) if bid<=last<=ask else last
852
+ decimal_places = abs(Decimal(str(price)).as_tuple().exponent)
853
+
854
+ symbol = row['symbol']
855
+ positionId = row['positionId']
856
+ avgOpenPrice = float(row['avgOpenPrice'])
857
+ qty = float(row['qty'])
858
+
859
+ tpPrice = None
860
+ tporderId = None
861
+ old_tpPrice = None
862
+ tpStopType = self.settings.SL_STOP_TYPE
863
+ tpOrderType = self.settings.SL_ORDER_TYPE
864
+
865
+ slPrice = None
866
+ slorderId = None
867
+ old_slPrice = None
868
+ slStopType = self.settings.SL_STOP_TYPE
869
+ slOrderType = self.settings.SL_ORDER_TYPE
870
+
871
+ datajs = await self.bitunixApi.GetPendingTpSlOrderData({'symbol': symbol})
872
+ if datajs:
873
+ for order in datajs:
874
+ if order['tpPrice'] is not None:
875
+ tporderId = order['id']
876
+ tpStopType = order['tpStopType']
877
+ tpOrderType = order['tpOrderType']
878
+ tpPrice = float(order['tpPrice'])
879
+ old_tpPrice = tpPrice
880
+ if order['slPrice'] is not None:
881
+ slorderId = order['id']
882
+ slStopType = order['slStopType']
883
+ slOrderType = order['slOrderType']
884
+ slPrice = float(order['slPrice'])
885
+ old_slPrice = slPrice
886
+
887
+ # move TP and SL in the direction of profit
888
+ midpoint = tpPrice / (1 + self.settings.PROFIT_PERCENTAGE/100/self.settings.LEVERAGE) if side == "BUY" else tpPrice / (1 - self.settings.PROFIT_PERCENTAGE/100/self.settings.LEVERAGE) if tpPrice is not None else None
889
+ if price > midpoint and side == "BUY" or price < midpoint and side == "SELL":
890
+
891
+ tpPrice = 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)
892
+ tpPrice = Decimal(await self.str_precision(tpPrice))
893
+ tpPrice =float(str(tpPrice.quantize(Decimal(f'1e-{decimal_places}'))))
894
+ tpOrderPrice = await self.decrement_by_last_decimal(str(tpPrice))
895
+
896
+ 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)
897
+ slPrice = Decimal(await self.str_precision(slPrice))
898
+ slPrice = float(str(slPrice.quantize(Decimal(f'1e-{decimal_places}'))))
899
+ slOrderPrice = await self.increment_by_last_decimal(await self.str_precision(slPrice))
900
+
901
+ self.notifications.add_notification(
902
+ f'{colors.CYAN} {row.symbol} TP/SL midpoint is at {midpoint}'
903
+ )
904
+ datajs3 = await self.bitunixApi.ModifyTpSlOrder({'orderId':slorderId,'slPrice':str(slPrice),'slQty':str(qty),'slStopType':slStopType,'slOrderType':slOrderType})
905
+ if datajs3 is not None:
906
+ self.notifications.add_notification(
907
+ f'{colors.CYAN} Stop Loss order for {row.symbol} moved from {old_slPrice} to {slPrice}'
908
+ )
909
+ datajs2 = await self.bitunixApi.ModifyTpSlOrder({'orderId':tporderId,'tpPrice':str(tpPrice), 'tpOrderPrice':str(tpOrderPrice), 'tpQty':str(qty),'tpStopType':tpStopType,'tpOrderType':tpOrderType})
910
+ if datajs2 is not None:
911
+ self.notifications.add_notification(
912
+ f'{colors.CYAN} Take Profit order for {row.symbol} moved from {old_tpPrice} to {tpPrice}'
913
+ )
914
+
915
+
916
+ if self.settings.BOT_CONTROLS_TP_SL:
842
917
  # check take profit amount or accept loss amount
843
918
  if float(self.settings.LOSS_AMOUNT) > 0 and total_pnl < -float(self.settings.LOSS_AMOUNT):
844
919
  last, bid, ask, mtv = await self.GetTickerBidLastAsk(row.symbol)
@@ -319,20 +319,16 @@ class Interval:
319
319
  df.replace([np.inf, -np.inf], 0, inplace=True)
320
320
 
321
321
  if self.settings.OPEN_ON_ANY_SIGNAL:
322
- # If EMA is enabled and crossing or MACD is enabled and crossing or BBM is enabled and crossing or RSI is enbabled and crossing
323
- # and
324
- # ADX is enabled and strong and candle trend is enabled and bullish
325
- # then BUY or SELL
326
322
 
327
323
  # Check for BUY signal
328
- buy_conditions = (
329
- (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "BUY") or
330
- (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "BUY") or
331
- (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_OPEN and self.macd_signal == "BUY") or
332
- (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_OPEN and self.bbm_signal == "BUY") or
333
- (self.settings.RSI_STUDY and self.settings.RSI_CHECK_ON_OPEN and self.rsi_signal == "BUY") or
334
- (self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_OPEN and self.trendline_signal == "BUY")
335
- )
324
+ ema_open = (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "BUY")
325
+ macd_open = (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_OPEN and self.macd_signal == "BUY")
326
+ bbm_open = (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_OPEN and self.bbm_signal == "BUY")
327
+ rsi_open = (self.settings.RSI_STUDY and self.settings.RSI_CHECK_ON_OPEN and self.rsi_signal == "BUY")
328
+ bos_open = (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "BUY")
329
+ trendline_open = (self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_OPEN and self.trendline_signal == "BUY")
330
+
331
+ buy_conditions = ema_open or macd_open or bbm_open or rsi_open or bos_open or trendline_open
336
332
  additional_buy_conditions = (
337
333
  (not self.settings.ADX_STUDY or not self.settings.ADX_CHECK_ON_OPEN or self.adx_signal == "STRONG") and
338
334
  (not self.settings.CANDLE_TREND_STUDY or not self.settings.CANDLE_TREND_CHECK_ON_OPEN or self.candle_trend == "BULLISH")
@@ -340,14 +336,14 @@ class Interval:
340
336
 
341
337
 
342
338
  # Check for SELL signal
343
- sell_conditions = (
344
- (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "SELL") or
345
- (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "SELL") or
346
- (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_OPEN and self.macd_signal == "SELL") or
347
- (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_OPEN and self.bbm_signal == "SELL") or
348
- (self.settings.RSI_STUDY and self.settings.RSI_CHECK_ON_OPEN and self.rsi_signal == "SELL") or
349
- (self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_OPEN and self.trendline_signal == "SELL")
350
- )
339
+ ema_close = (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_CLOSE and self.ema_close_signal == "SELL")
340
+ macd_close = (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_CLOSE and self.macd_signal == "SELL")
341
+ bbm_close = (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_CLOSE and self.bbm_signal == "SELL")
342
+ rsi_close = (self.settings.RSI_STUDY and self.settings.RSI_CHECK_ON_CLOSE and self.rsi_signal == "SELL")
343
+ bos_close = (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_CLOSE and self.bos_signal == "SELL")
344
+ trendline_close = (self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_CLOSE and self.trendline_signal == "SELL")
345
+
346
+ sell_conditions = ema_close or macd_close or bbm_close or rsi_close or bos_close or trendline_close
351
347
  additional_sell_conditions = (
352
348
  (self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN and self.adx_signal == "STRONG") and
353
349
  (self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN or self.candle_trend == "BEARISH")
@@ -361,68 +357,40 @@ class Interval:
361
357
  else:
362
358
  self.current_signal = "HOLD"
363
359
  else:
364
- buy_conditions = (
365
- (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "BUY")
366
- or not self.settings.BOS_STUDY
367
- ) and (
368
- (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "BUY")
369
- or not self.settings.EMA_STUDY or not self.settings.EMA_CHECK_ON_OPEN
370
- ) and (
371
- (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_OPEN and self.macd_signal == "BUY")
372
- or not self.settings.MACD_STUDY or not self.settings.MACD_CHECK_ON_OPEN
373
- ) and (
374
- (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_OPEN and self.bbm_signal == "BUY")
360
+ ema_open =(self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "BUY") \
361
+ or not self.settings.EMA_STUDY or not self.settings.EMA_CHECK_ON_OPEN
362
+ macd_open = (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_OPEN and self.macd_signal == "BUY") \
363
+ or not self.settings.MACD_STUDY or not self.settings.MACD_CHECK_ON_OPEN
364
+ bbm_open = (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_OPEN and self.bbm_signal == "BUY") \
375
365
  or not self.settings.BBM_STUDY or not self.settings.BBM_CHECK_ON_OPEN
376
- ) and (
377
- (self.settings.RSI_STUDY and self.settings.RSI_CHECK_ON_OPEN and self.rsi_signal == "BUY")
366
+ rsi_open = (self.settings.RSI_STUDY and self.settings.RSI_CHECK_ON_OPEN and self.rsi_signal == "BUY") \
378
367
  or not self.settings.RSI_STUDY or not self.settings.RSI_CHECK_ON_OPEN
379
- ) and (
380
- (self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_OPEN and self.trendline_signal == "BUY")
368
+ bos_open = (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "BUY") \
369
+ or not self.settings.BOS_STUDY or not self.settings.BOS_CHECK_ON_OPEN
370
+ trendline_open = (self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_OPEN and self.trendline_signal == "BUY") \
381
371
  or not self.settings.TRENDLINE_STUDY or not self.settings.TRENDLINE_CHECK_ON_OPEN
382
- )
383
- if not any([
384
- self.settings.EMA_STUDY, self.settings.MACD_STUDY, self.settings.BBM_STUDY,
385
- self.settings.RSI_STUDY, self.settings.TRENDLINE_STUDY
386
- ]) and not any([
387
- self.settings.EMA_CHECK_ON_OPEN, self.settings.MACD_CHECK_ON_OPEN, self.settings.BBM_CHECK_ON_OPEN,
388
- self.settings.RSI_CHECK_ON_OPEN, self.settings.TRENDLINE_CHECK_ON_OPEN
389
- ]):
390
- buy_conditions = False
391
372
 
373
+ buy_conditions = ema_open and macd_open and bbm_open and rsi_open and bos_open and trendline_open
392
374
  additional_buy_conditions = (
393
375
  (not self.settings.ADX_STUDY or not self.settings.ADX_CHECK_ON_OPEN or self.adx_signal == "STRONG") and
394
376
  (not self.settings.CANDLE_TREND_STUDY or not self.settings.CANDLE_TREND_CHECK_ON_OPEN or self.candle_trend == "BULLISH")
395
377
  )
396
378
 
397
379
  # Check for SELL signal
398
- sell_conditions = (
399
- (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "SELL")
400
- or not self.settings.BOS_STUDY
401
- ) and (
402
- (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "SELL")
403
- or not self.settings.EMA_STUDY or not self.settings.EMA_CHECK_ON_OPEN
404
- ) and (
405
- (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_OPEN and self.macd_signal == "SELL")
406
- or not self.settings.MACD_STUDY or not self.settings.MACD_CHECK_ON_OPEN
407
- ) and (
408
- (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_OPEN and self.bbm_signal == "SELL")
409
- or not self.settings.BBM_STUDY or not self.settings.BBM_CHECK_ON_OPEN
410
- ) and (
411
- (self.settings.RSI_STUDY and self.settings.RSI_CHECK_ON_OPEN and self.rsi_signal == "SELL")
412
- or not self.settings.RSI_STUDY or not self.settings.RSI_CHECK_ON_OPEN
413
- ) and (
414
- (self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_OPEN and self.trendline_signal == "SELL")
415
- or not self.settings.TRENDLINE_STUDY or not self.settings.TRENDLINE_CHECK_ON_OPEN
416
- )
417
- if not any([
418
- self.settings.EMA_STUDY, self.settings.MACD_STUDY, self.settings.BBM_STUDY,
419
- self.settings.RSI_STUDY, self.settings.TRENDLINE_STUDY
420
- ]) and not any([
421
- self.settings.EMA_CHECK_ON_OPEN, self.settings.MACD_CHECK_ON_OPEN, self.settings.BBM_CHECK_ON_OPEN,
422
- self.settings.RSI_CHECK_ON_OPEN, self.settings.TRENDLINE_CHECK_ON_OPEN
423
- ]):
424
- sell_conditions = False
425
-
380
+ ema_close= (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_CLOSE and self.ema_close_signal == "SELL") \
381
+ or not self.settings.EMA_STUDY or not self.settings.EMA_CHECK_ON_CLOSE
382
+ macd_close = (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_CLOSE and self.macd_signal == "SELL") \
383
+ or not self.settings.MACD_STUDY or not self.settings.MACD_CHECK_ON_CLOSE
384
+ bbm_close = (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_CLOSE and self.bbm_signal == "SELL") \
385
+ or not self.settings.BBM_STUDY or not self.settings.BBM_CHECK_ON_CLOSE
386
+ rsi_close = (self.settings.RSI_STUDY and self.settings.RSI_CHECK_ON_CLOSE and self.rsi_signal == "SELL") \
387
+ or not self.settings.RSI_STUDY or not self.settings.RSI_CHECK_ON_CLOSE
388
+ bos_close = (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_CLOSE and self.bos_signal == "SELL") \
389
+ or not self.settings.BOS_STUDY or not self.settings.BOS_CHECK_ON_CLOSE
390
+ trendline_close = (self.settings.TRENDLINE_STUDY and self.settings.TRENDLINE_CHECK_ON_CLOSE and self.trendline_signal == "SELL") \
391
+ or not self.settings.TRENDLINE_STUDY or not self.settings.TRENDLINE_CHECK_ON_CLOSE
392
+
393
+ sell_conditions = ema_close and macd_close and bbm_close and rsi_close and bos_close and trendline_close
426
394
  additional_sell_conditions = (
427
395
  (self.settings.ADX_STUDY and self.settings.ADX_CHECK_ON_OPEN and self.adx_signal == "STRONG") or
428
396
  (self.settings.CANDLE_TREND_STUDY and self.settings.CANDLE_TREND_CHECK_ON_OPEN or self.candle_trend == "BEARISH")
@@ -21,11 +21,12 @@ class Settings(BaseSettings):
21
21
  LOSS_PERCENTAGE: float = Field(default=10, ge=0.0)
22
22
  PROFIT_AMOUNT: float = Field(default=0, ge=0.0)
23
23
  LOSS_AMOUNT: float = Field(default=5.0, ge=0.0)
24
- BOT_TAKE_PROFIT_STOP_LOSS: bool = Field(default=False)
25
- TAKE_PROFIT_PRICE_TYPE: str = Field(default="MARK_PRICE")
26
- TAKE_PROFIT_ORDER_TYPE: str = Field(default="LIMIT")
27
- STOP_LOSS_PRICE_TYPE: str = Field(default="MARK_PRICE")
28
- STOP_LOSS_ORDER_TYPE: str = Field(default="MARKET")
24
+ BOT_CONTROLS_TP_SL: bool = Field(default=False)
25
+ BOT_TRAIL_TP_SL: bool = Field(default=False)
26
+ TP_STOP_TYPE: str = Field(default="MARK_PRICE")
27
+ TP_ORDER_TYPE: str = Field(default="LIMIT")
28
+ SL_STOP_TYPE: str = Field(default="MARK_PRICE")
29
+ SL_ORDER_TYPE: str = Field(default="MARKET")
29
30
  OPTION_MOVING_AVERAGE: str = Field(default="1h")
30
31
  DELAY_IN_MINUTES_FOR_SAME_TICKER_TRADES: int = Field(default=15, ge=0)
31
32
  BARS: int = Field(default=100, ge=1)
@@ -1 +1 @@
1
- __version__ = "3.3.2"
1
+ __version__ = "3.3.5"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bitunix_automated_crypto_trading
3
- Version: 3.3.2
3
+ Version: 3.3.5
4
4
  Summary: Bitunix Futures Auto Trading Platform
5
5
  Home-page: https://github.com/tcj2001/bitunix-automated-crypto-trading
6
6
  Author: tcj2001
@@ -1,19 +1,19 @@
1
1
  bitunix_automated_crypto_trading/AsyncThreadRunner.py,sha256=bNIM_1xRYQOFEsIn74EX6qVpC59-GMhhr2CeiPr_GWg,3253
2
- bitunix_automated_crypto_trading/BitunixApi.py,sha256=4iiqiN3uvX6-bmZ5WtG3pt1No0C6eNlqdLA5jylXRp8,13496
3
- bitunix_automated_crypto_trading/BitunixSignal.py,sha256=rVoVBSb3T3Zw-lJt1s4gRV-e8tZSZu4EINdbiilQgUc,82493
2
+ bitunix_automated_crypto_trading/BitunixApi.py,sha256=5qg-K5IcsAbb6K1feP9zL7RzSz7JzdGAxoY8R_YWxWE,15666
3
+ bitunix_automated_crypto_trading/BitunixSignal.py,sha256=ke8KNlorfmmifTWhdFPUR63Zsl__gPRdalAqcdR6zSo,88174
4
4
  bitunix_automated_crypto_trading/BitunixWebSocket.py,sha256=uiqAcis3u-ct07tjaTiC87ujzvcAtVRZ31CMiTBDW_M,11309
5
5
  bitunix_automated_crypto_trading/DataFrameHtmlRenderer.py,sha256=Pqdzhh_nfIxFEZH9L_R5QXB8moDPbgeTGT_hmBkHWMg,2899
6
6
  bitunix_automated_crypto_trading/NotificationManager.py,sha256=exs6REABBA1omTeTGuUuECzxs5dGqdyL7oI8WyxS6Xc,798
7
7
  bitunix_automated_crypto_trading/SupportResistance.py,sha256=x_to4M4OHg0h8o40DXDBa4E_5io-y2Lb5qo2VzFnu_8,5765
8
8
  bitunix_automated_crypto_trading/ThreadManager.py,sha256=Lw5_1EIT0m3AFSv5CIMpnjtA0DnNw2qQ6JtSpT34LyM,2349
9
- bitunix_automated_crypto_trading/TickerManager.py,sha256=E6U08wO1LKY4XctB6frtoAmlactMng3xwRrqG59qDt8,43030
9
+ bitunix_automated_crypto_trading/TickerManager.py,sha256=CLd7pvE-qyYBPBauy--A54z7srmMMJsiaWcrY4ezFFU,41939
10
10
  bitunix_automated_crypto_trading/__init__.py,sha256=1hzk6nX8NnUCr1tsq8oFq1qGCNhNwnwldWE75641Eew,78
11
11
  bitunix_automated_crypto_trading/bitunix.py,sha256=lxwnYARxldA2oU6GdjupilXIlnUh4RX8rQLCOn7x13I,27143
12
- bitunix_automated_crypto_trading/config.py,sha256=OASGCVl0avfVSLqdaZC4fxFSiVIrmdMvin3wJMB3Kq0,5830
12
+ bitunix_automated_crypto_trading/config.py,sha256=J-YIrcbS-FOlLze1QvAocelYPA53thJODVyhuZwQW5E,5838
13
13
  bitunix_automated_crypto_trading/logger.py,sha256=NHnA5JZdUFkTAhB7i-1iCAwrdf1fxhDuRvJUkbKPi9Y,2923
14
- bitunix_automated_crypto_trading/version.py,sha256=atqyGOnhrhSlkFH4WgeEJ48n-b00QDPSS9LvTLmvhmU,21
15
- bitunix_automated_crypto_trading-3.3.2.dist-info/METADATA,sha256=m_1FPUbtyZuXsTNhtwPOAZRSiKclI6kdnJ7O2HIudmo,996
16
- bitunix_automated_crypto_trading-3.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- bitunix_automated_crypto_trading-3.3.2.dist-info/entry_points.txt,sha256=UXREYHuSl2XYd_tOtLIq0zg3d1kX3lixX5SpN8yGBw4,82
18
- bitunix_automated_crypto_trading-3.3.2.dist-info/top_level.txt,sha256=uyFzHUCOsp8elnG2Ovor6xXcf7dxRxY-C-Txiwix64Q,33
19
- bitunix_automated_crypto_trading-3.3.2.dist-info/RECORD,,
14
+ bitunix_automated_crypto_trading/version.py,sha256=tC7feJeEXvyWQbCx5glWxCoo1hKMycavaWn-uadNZ0E,21
15
+ bitunix_automated_crypto_trading-3.3.5.dist-info/METADATA,sha256=gQpnt3MalX-CV_EokXNyadl2q679NfFj2Cw8bgtzudg,996
16
+ bitunix_automated_crypto_trading-3.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ bitunix_automated_crypto_trading-3.3.5.dist-info/entry_points.txt,sha256=UXREYHuSl2XYd_tOtLIq0zg3d1kX3lixX5SpN8yGBw4,82
18
+ bitunix_automated_crypto_trading-3.3.5.dist-info/top_level.txt,sha256=uyFzHUCOsp8elnG2Ovor6xXcf7dxRxY-C-Txiwix64Q,33
19
+ bitunix_automated_crypto_trading-3.3.5.dist-info/RECORD,,