bitunix-automated-crypto-trading 3.1.2__py3-none-any.whl → 3.1.3__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.
@@ -258,6 +258,8 @@ class BitunixApi:
258
258
  url = f'{self.kline_Url}?symbol={ticker}&startTime={st}&interval={interval}&limit={lm}'
259
259
  resp = self.session.get(url)
260
260
  datajs = resp.json()
261
+ if datajs['data'] == []:
262
+ break
261
263
  data.extend(datajs['data'])
262
264
  if len(datajs['data']) < lm:
263
265
  st = int(datajs['data'][-1]['time']) + 1
@@ -110,7 +110,8 @@ class BitunixSignal:
110
110
  olist = [entry['symbol'] for entry in self.pendingOrders['orderList']]
111
111
  newlist=olist+plist+list(set(symbols))
112
112
  self.tickerList=newlist[:300]
113
- #self.tickerList=['IMXUSDT']
113
+ self.tickerList.remove("STMXUSDT")
114
+ #self.tickerList=['PIXELUSDT']
114
115
 
115
116
  [await self.add_ticker_to_tickerObjects(sym) for sym in self.tickerList]
116
117
  self.notifications.add_notification(f"{len(self.tickerList)} ticker list loaded")
@@ -397,7 +398,7 @@ class BitunixSignal:
397
398
  self.notifications.add_notification("AutoTradeProcess or GetTickerData is not running")
398
399
  os._exit(1)
399
400
  break
400
- await asyncio.sleep(300)
401
+ await asyncio.sleep(60*30)
401
402
 
402
403
  async def GetportfolioData(self):
403
404
  start=time.time()
@@ -36,11 +36,57 @@ class Interval:
36
36
  return self._data
37
37
 
38
38
  def set_data(self, new_value):
39
- self._data = self.calculate_study(new_value)
40
-
39
+ study = self.calculate_study(new_value)
40
+ self._data = study
41
+
42
+ def support_resistance_trend_lines(self, data, lookback=20):
43
+ recent_data = data[-lookback:]
44
+ high_prices = recent_data['high'].values
45
+ low_prices = recent_data['low'].values
46
+ candle_indices = np.arange(lookback)
47
+ ts = recent_data['time']
48
+
49
+ # 1. Identify highest high and lowest low candle
50
+ highest_high_index = np.argmax(high_prices)
51
+ lowest_low_index = np.argmin(low_prices)
52
+ highest_high_price = high_prices[highest_high_index]
53
+ lowest_low_price = low_prices[lowest_low_index]
54
+
55
+ # 2. Top line: Tilt down from highest high to touch a subsequent high (if any)
56
+ slope_top = -float('inf') # Initialize with a very steep negative slope
57
+ intercept_top = highest_high_price - slope_top * highest_high_index
58
+
59
+ for i in range(highest_high_index + 1, lookback):
60
+ current_slope = (high_prices[i] - highest_high_price) / (i - highest_high_index) if (i - highest_high_index) != 0 else 0
61
+ if current_slope > slope_top:
62
+ slope_top = current_slope
63
+ intercept_top = highest_high_price - slope_top * highest_high_index
64
+
65
+ top_line = slope_top * candle_indices + intercept_top
66
+
67
+ # 3. Bottom line: Tilt up from lowest low to touch a subsequent low (if any)
68
+ slope_bottom = float('inf') # Initialize with a very steep positive slope
69
+ intercept_bottom = lowest_low_price - slope_bottom * lowest_low_index
70
+
71
+ for i in range(lowest_low_index + 1, lookback):
72
+ current_slope = (low_prices[i] - lowest_low_price) / (i - lowest_low_index) if (i - lowest_low_index) != 0 else 0
73
+ if current_slope < slope_bottom:
74
+ slope_bottom = current_slope
75
+ intercept_bottom = lowest_low_price - slope_bottom * lowest_low_index
76
+
77
+ bottom_line = slope_bottom * candle_indices + intercept_bottom
78
+
79
+ results_df = pd.DataFrame({
80
+ 'time': ts,
81
+ 'top_line': top_line,
82
+ 'bottom_line': bottom_line
83
+ })
84
+
85
+ return results_df
86
+
41
87
  def calculate_study(self, new_value):
42
88
  df = pd.DataFrame(new_value)
43
- if not df.empty and df.shape[0] >= int(self.settings.BARS):
89
+ if not df.empty: #and df.shape[0] >= int(self.settings.BARS):
44
90
 
45
91
  try:
46
92
  #consecutive same color candle
@@ -53,54 +99,56 @@ class Interval:
53
99
  # Calculate the Moving Averages
54
100
  if self.settings.EMA_STUDY:
55
101
  df['ma_fast'] = talib.EMA(df['close'], timeperiod=self.settings.MA_FAST)
56
- df.dropna(subset=['ma_fast'], inplace=True)
102
+ df.fillna({'ma_fast':0}, inplace=True)
57
103
  df['ma_fast_slope'] = df['ma_fast'].diff()
58
104
  df['ma_fast_angle'] = np.degrees(np.arctan(df['ma_fast_slope']))
59
105
  df.fillna({'ma_fast_slope':0}, inplace=True)
60
106
  df.fillna({'ma_fast_angle':0}, inplace=True)
61
107
 
62
108
  df['ma_medium'] = talib.EMA(df['close'], timeperiod=self.settings.MA_MEDIUM)
63
- df.dropna(subset=['ma_medium'], inplace=True)
109
+ df.fillna({'ma_medium':0}, inplace=True)
64
110
  df['ma_medium_slope'] = df['ma_medium'].diff()
65
111
  df['ma_medium_angle'] = np.degrees(np.arctan(df['ma_medium_slope']))
66
112
  df.fillna({'ma_medium_slope':0}, inplace=True)
67
113
  df.fillna({'ma_medium_angle':0}, inplace=True)
68
114
 
69
115
  df['ma_slow'] = talib.EMA(df['close'], timeperiod=self.settings.MA_SLOW)
70
- df.dropna(subset=['ma_slow'],inplace=True)
116
+ df.fillna({'ma_slow':0}, inplace=True)
71
117
  df['ma_slow_slope'] = df['ma_slow'].diff()
72
118
  df['ma_slow_angle'] = np.degrees(np.arctan(df['ma_slow_slope']))
73
119
  df.fillna({'ma_slow_slope':0}, inplace=True)
74
120
  df.fillna({'ma_slow_angle':0}, inplace=True)
75
121
 
76
122
  if self.settings.EMA_CROSSING:
77
- if df['ma_medium'].iloc[-2] <= df['ma_slow'].iloc[-2] and df['ma_medium'].iloc[-1] > df['ma_slow'].iloc[-1]:
78
- self.ema_open_signal = "BUY"
79
- self.ema_close_signal = "BUY"
80
- elif df['ma_medium'].iloc[-2] >= df['ma_slow'].iloc[-2] and df['ma_medium'].iloc[-1] < df['ma_slow'].iloc[-1]:
81
- self.ema_open_signal = "SELL"
82
- self.ema_close_signal = "SELL"
83
- else:
84
- self.ema_open_signal = "HOLD"
85
- self.ema_close_signal = "HOLD"
86
-
87
- if self.settings.EMA_CLOSE_ON_FAST_MEDIUM:
88
- if df['ma_fast'].iloc[-2] <= df['ma_medium'].iloc[-2] and df['ma_fast'].iloc[-1] > df['ma_medium'].iloc[-1]:
123
+ if df is not None and len(df) >= 2:
124
+ if df['ma_medium'].iloc[-2] <= df['ma_slow'].iloc[-2] and df['ma_medium'].iloc[-1] > df['ma_slow'].iloc[-1]:
125
+ self.ema_open_signal = "BUY"
89
126
  self.ema_close_signal = "BUY"
90
- elif df['ma_fast'].iloc[-2] >= df['ma_medium'].iloc[-2] and df['ma_fast'].iloc[-1] < df['ma_medium'].iloc[-1]:
127
+ elif df['ma_medium'].iloc[-2] >= df['ma_slow'].iloc[-2] and df['ma_medium'].iloc[-1] < df['ma_slow'].iloc[-1]:
128
+ self.ema_open_signal = "SELL"
91
129
  self.ema_close_signal = "SELL"
92
130
  else:
131
+ self.ema_open_signal = "HOLD"
93
132
  self.ema_close_signal = "HOLD"
133
+
134
+ if self.settings.EMA_CLOSE_ON_FAST_MEDIUM:
135
+ if df['ma_fast'].iloc[-2] <= df['ma_medium'].iloc[-2] and df['ma_fast'].iloc[-1] > df['ma_medium'].iloc[-1]:
136
+ self.ema_close_signal = "BUY"
137
+ elif df['ma_fast'].iloc[-2] >= df['ma_medium'].iloc[-2] and df['ma_fast'].iloc[-1] < df['ma_medium'].iloc[-1]:
138
+ self.ema_close_signal = "SELL"
139
+ else:
140
+ self.ema_close_signal = "HOLD"
94
141
  else:
95
- if df['close'].iloc[-1] > df['ma_medium'].iloc[-1] and df['ma_medium'].iloc[-1] > df['ma_slow'].iloc[-1]:
96
- self.ema_open_signal = "BUY"
97
- self.ema_close_signal = "BUY"
98
- elif df['close'].iloc[-1] < df['ma_medium'].iloc[-1] and df['ma_medium'].iloc[-1] < df['ma_slow'].iloc[-1]:
99
- self.ema_open_signal = "SELL"
100
- self.ema_close_signal = "SELL"
101
- else:
102
- self.ema_open_signal = "HOLD"
103
- self.ema_close_signal = "HOLD"
142
+ if df is not None and len(df) >= 1:
143
+ if df['close'].iloc[-1] > df['ma_medium'].iloc[-1] and df['ma_medium'].iloc[-1] > df['ma_slow'].iloc[-1]:
144
+ self.ema_open_signal = "BUY"
145
+ self.ema_close_signal = "BUY"
146
+ elif df['close'].iloc[-1] < df['ma_medium'].iloc[-1] and df['ma_medium'].iloc[-1] < df['ma_slow'].iloc[-1]:
147
+ self.ema_open_signal = "SELL"
148
+ self.ema_close_signal = "SELL"
149
+ else:
150
+ self.ema_open_signal = "HOLD"
151
+ self.ema_close_signal = "HOLD"
104
152
  else:
105
153
  # Drop EMA columns if not used
106
154
  df.drop(['ma_fast', 'ma_medium', 'ma_slow', 'ma_slope', 'ma_angle'], axis=1, inplace=True, errors='ignore')
@@ -111,7 +159,7 @@ class Interval:
111
159
  df['MACD_Signal'] = 0.0
112
160
  df['MACD_Histogram'] = 0.0
113
161
  df['MACD_Line'], df['MACD_Signal'], df['MACD_Histogram'] = talib.MACD(df['close'], fastperiod=self.settings.MACD_SHORT, slowperiod=self.settings.MACD_LONG, signalperiod=self.settings.MACD_PERIOD)
114
- df.dropna(subset=['MACD_Line', 'MACD_Signal', 'MACD_Histogram'], inplace=True)
162
+ df.fillna({'MACD_Line':0, 'MACD_Signal':0, 'MACD_Histogram':0}, inplace=True)
115
163
  df['MACD_Line_slope'] = df['MACD_Line'].diff()
116
164
  df['MACD_Line_angle'] = np.degrees(np.arctan(df['MACD_Line_slope']))
117
165
  df.fillna({'MACD_Line_slope':0}, inplace=True)
@@ -119,19 +167,21 @@ class Interval:
119
167
 
120
168
 
121
169
  if self.settings.MACD_CROSSING:
122
- if df['MACD_Line'].iloc[-2] <= df['MACD_Signal'].iloc[-2] and df['MACD_Line'].iloc[-1] > df['MACD_Signal'].iloc[-1]:
123
- self.macd_signal = "BUY"
124
- elif df['MACD_Line'].iloc[-2] >= df['MACD_Signal'].iloc[-2] and df['MACD_Line'].iloc[-1] < df['MACD_Signal'].iloc[-1]:
125
- self.macd_signal = "SELL"
126
- else:
127
- self.macd_signal = "HOLD"
170
+ if df is not None and len(df) >= 2:
171
+ if df['MACD_Line'].iloc[-2] <= df['MACD_Signal'].iloc[-2] and df['MACD_Line'].iloc[-1] > df['MACD_Signal'].iloc[-1]:
172
+ self.macd_signal = "BUY"
173
+ elif df['MACD_Line'].iloc[-2] >= df['MACD_Signal'].iloc[-2] and df['MACD_Line'].iloc[-1] < df['MACD_Signal'].iloc[-1]:
174
+ self.macd_signal = "SELL"
175
+ else:
176
+ self.macd_signal = "HOLD"
128
177
  else:
129
- if df['MACD_Line'].iloc[-1] > df['MACD_Signal'].iloc[-1]:
130
- self.macd_signal = "BUY"
131
- elif df['MACD_Line'].iloc[-1] < df['MACD_Signal'].iloc[-1]:
132
- self.macd_signal = "SELL"
133
- else:
134
- self.macd_signal = "HOLD"
178
+ if df is not None and len(df) >= 1:
179
+ if df['MACD_Line'].iloc[-1] > df['MACD_Signal'].iloc[-1]:
180
+ self.macd_signal = "BUY"
181
+ elif df['MACD_Line'].iloc[-1] < df['MACD_Signal'].iloc[-1]:
182
+ self.macd_signal = "SELL"
183
+ else:
184
+ self.macd_signal = "HOLD"
135
185
  else:
136
186
  # Drop MACD columns if not used
137
187
  df.drop(['MACD_Line', 'MACD_Signal', 'MACD_Histogram', 'MACD_slope', 'MACD_angle'], axis=1, inplace=True, errors='ignore')
@@ -142,7 +192,7 @@ class Interval:
142
192
  df['BBM'] = 0.0
143
193
  df['BBU'] = 0.0
144
194
  df['BBU'], df['BBM'], df['BBL'] = talib.BBANDS(df['close'], timeperiod=self.settings.BBM_PERIOD, nbdevup=self.settings.BBM_STD, nbdevdn=self.settings.BBM_STD, )
145
- df.dropna(subset=['BBM', 'BBU', 'BBL'], inplace=True)
195
+ df.fillna({'BBM':0, 'BBU':0, 'BBL':0}, inplace=True)
146
196
 
147
197
  df['BBM_slope'] = df['BBM'].diff()
148
198
  df['BBM_angle'] = np.degrees(np.arctan(df['BBM_slope']))
@@ -150,19 +200,21 @@ class Interval:
150
200
  df.fillna({'BBM_angle':0}, inplace=True)
151
201
 
152
202
  if self.settings.BBM_CROSSING:
153
- if df['close'].iloc[-2] <= df['BBM'].iloc[-2] and df['close'].iloc[-1] > df['BBM'].iloc[-1]:
154
- self.bbm_signal = "BUY"
155
- elif df['close'].iloc[-2] >= df['BBM'].iloc[-2] and df['close'].iloc[-1] < df['BBM'].iloc[-1]:
156
- self.bbm_signal = "SELL"
157
- else:
158
- self.bbm_signal = "HOLD"
203
+ if df is not None and len(df) >= 2:
204
+ if df['close'].iloc[-2] <= df['BBM'].iloc[-2] and df['close'].iloc[-1] > df['BBM'].iloc[-1]:
205
+ self.bbm_signal = "BUY"
206
+ elif df['close'].iloc[-2] >= df['BBM'].iloc[-2] and df['close'].iloc[-1] < df['BBM'].iloc[-1]:
207
+ self.bbm_signal = "SELL"
208
+ else:
209
+ self.bbm_signal = "HOLD"
159
210
  else:
160
- if df['close'].iloc[-1] > df['BBM'].iloc[-1] and df['close'].iloc[-2] > df['BBM'].iloc[-2]:
161
- self.bbm_signal = "BUY"
162
- elif df['close'].iloc[-1] < df['BBM'].iloc[-1] and df['close'].iloc[-2] < df['BBM'].iloc[-2]:
163
- self.bbm_signal = "SELL"
164
- else:
165
- self.bbm_signal = "HOLD"
211
+ if df is not None and len(df) >= 1:
212
+ if df['close'].iloc[-1] > df['BBM'].iloc[-1]:
213
+ self.bbm_signal = "BUY"
214
+ elif df['close'].iloc[-1] < df['BBM'].iloc[-1]:
215
+ self.bbm_signal = "SELL"
216
+ else:
217
+ self.bbm_signal = "HOLD"
166
218
  else:
167
219
  # Drop BBM columns if not used
168
220
  df.drop(['BBL', 'BBM', 'BBU', 'BBM_slope', 'BBM_angle'], axis=1, inplace=True, errors='ignore')
@@ -170,14 +222,14 @@ class Interval:
170
222
  # Calculate the RSI
171
223
  if self.settings.RSI_STUDY:
172
224
  df['rsi_fast'] = talib.RSI(df['close'],timeperiod=self.settings.RSI_FAST)
173
- df.dropna(subset=['rsi_fast'], inplace=True)
225
+ df.fillna({'rsi_fast':0}, inplace=True)
174
226
  df['rsi_fast_slope'] = df['rsi_fast'].diff()
175
227
  df['rsi_fast_angle'] = np.degrees(np.arctan(df['rsi_fast_slope']))
176
228
  df.fillna({'rsi_fast_slope':0}, inplace=True)
177
229
  df.fillna({'rsi_fast_angle':0}, inplace=True)
178
230
 
179
231
  df['rsi_slow'] = talib.RSI(df['close'],timeperiod=self.settings.RSI_SLOW)
180
- df.dropna(subset=['rsi_slow'], inplace=True)
232
+ df.fillna({'rsi_slow':0}, inplace=True)
181
233
  df['rsi_slow_slope'] = df['rsi_slow'].diff()
182
234
  df['rsi_slow_angle'] = np.degrees(np.arctan(df['rsi_slow_slope']))
183
235
  df.fillna({'rsi_slow_slope':0}, inplace=True)
@@ -185,54 +237,69 @@ class Interval:
185
237
 
186
238
 
187
239
  if self.settings.RSI_CROSSING:
188
- if df['rsi_fast'].iloc[-2] <= df['rsi_slow'].iloc[-2] and df['rsi_fast'].iloc[-1] > df['rsi_slow'].iloc[-1]:
189
- self.rsi_signal = "BUY"
190
- elif df['rsi_fast'].iloc[-2] >= df['rsi_slow'].iloc[-2] and df['rsi_fast'].iloc[-1] < df['rsi_slow'].iloc[-1]:
191
- self.rsi_signal = "SELL"
192
- else:
193
- self.rsi_signal = "HOLD"
240
+ if df is not None and len(df) >= 2:
241
+ if df['rsi_fast'].iloc[-2] <= df['rsi_slow'].iloc[-2] and df['rsi_fast'].iloc[-1] > df['rsi_slow'].iloc[-1]:
242
+ self.rsi_signal = "BUY"
243
+ elif df['rsi_fast'].iloc[-2] >= df['rsi_slow'].iloc[-2] and df['rsi_fast'].iloc[-1] < df['rsi_slow'].iloc[-1]:
244
+ self.rsi_signal = "SELL"
245
+ else:
246
+ self.rsi_signal = "HOLD"
194
247
  else:
195
- if df['rsi_fast'].iloc[-1] > df['rsi_slow'].iloc[-1]:
196
- self.rsi_signal = "BUY"
197
- elif df['rsi_fast'].iloc[-1] < df['rsi_slow'].iloc[-1]:
198
- self.rsi_signal = "SELL"
199
- else:
200
- self.rsi_signal = "HOLD"
248
+ if df is not None and len(df) >= 1:
249
+ if df['rsi_fast'].iloc[-1] > df['rsi_slow'].iloc[-1]:
250
+ self.rsi_signal = "BUY"
251
+ elif df['rsi_fast'].iloc[-1] < df['rsi_slow'].iloc[-1]:
252
+ self.rsi_signal = "SELL"
253
+ else:
254
+ self.rsi_signal = "HOLD"
201
255
  else:
202
256
  # Drop RSI columns if not used
203
257
  df.drop(['rsi_fast', 'rsi_slow', 'rsi_slope', 'rsi_angle'], axis=1, inplace=True, errors='ignore')
204
258
 
259
+ #Trendline
260
+ if self.settings.TRENDLINE_STUDY:
261
+ lookback = self.settings.TRENDLINE_LOOKBACK
262
+ trend_df = self.support_resistance_trend_lines(df, lookback)
263
+
264
+ df['support_line'] = trend_df['top_line']
265
+ df.fillna({'support_line':0}, inplace=True)
266
+
267
+ df['resistance_line'] = trend_df['bottom_line']
268
+ df.fillna({'resistance_line':0}, inplace=True)
269
+
205
270
  # Calculate the ADX
206
271
  if self.settings.ADX_STUDY:
207
- df['ADX'] = talib.ADX(df['high'], df['low'], df['close'], timeperiod=self.settings.ADX_PERIOD)
208
- df.fillna({'ADX':0}, inplace=True)
209
- if df['ADX'].iloc[-1] > 25:
210
- self.adx_signal = "STRONG"
211
- else:
212
- self.adx_signal = "WEAK"
272
+ if df is not None and len(df) >= 1:
273
+ df['ADX'] = talib.ADX(df['high'], df['low'], df['close'], timeperiod=self.settings.ADX_PERIOD)
274
+ df.fillna({'ADX':0}, inplace=True)
275
+ if df['ADX'].iloc[-1] > 25:
276
+ self.adx_signal = "STRONG"
277
+ else:
278
+ self.adx_signal = "WEAK"
213
279
  else:
214
280
  # Drop ADX columns if not used
215
281
  df.drop(['ADX'], axis=1, inplace=True, errors='ignore')
216
282
 
217
283
  # Calculate the close proximity
218
284
  if self.settings.CANDLE_TREND_STUDY:
219
- df['range'] = df['high'] - df['low']
220
- df['candle_trend'] = ((df['close'] - df['low'])/df['range'])*100
221
- df.fillna({'candle_trend':0}, inplace=True)
222
- df.fillna({'range':0}, inplace=True)
223
-
224
- #open and close criteria
225
- if df['candle_trend'].iloc[-1] > 70:
226
- self.candle_trend = 'BULLISH'
227
- elif df['candle_trend'].iloc[-1] < 30:
228
- self.candle_trend = 'BEARISH'
229
- else:
230
- self.candle_trend = 'HOLD'
285
+ if df is not None and len(df) >= 1:
286
+ df['range'] = df['high'] - df['low']
287
+ df['candle_trend'] = ((df['close'] - df['low'])/df['range'])*100
288
+ df.fillna({'candle_trend':0}, inplace=True)
289
+ df.fillna({'range':0}, inplace=True)
290
+
291
+ #open and close criteria
292
+ if df['candle_trend'].iloc[-1] > 70:
293
+ self.candle_trend = 'BULLISH'
294
+ elif df['candle_trend'].iloc[-1] < 30:
295
+ self.candle_trend = 'BEARISH'
296
+ else:
297
+ self.candle_trend = 'HOLD'
231
298
  else:
232
299
  # Drop candle trend columns if not used
233
300
  df.drop(['candle_trend', 'range'], axis=1, inplace=True, errors='ignore')
234
301
 
235
-
302
+
236
303
  #replace infinity
237
304
  df.replace([np.inf, -np.inf], 0, inplace=True)
238
305
 
@@ -404,7 +471,8 @@ class Ticker:
404
471
  self._intervals = intervals
405
472
 
406
473
  def get_interval_ticks(self, intervalId):
407
- return self._intervals.get(intervalId, None)
474
+ interval = self._intervals.get(intervalId, None)
475
+ return interval
408
476
 
409
477
  def set_interval_ticks(self, intervalId, new_value):
410
478
  self._intervals[intervalId] = new_value
@@ -443,6 +511,7 @@ class Ticker:
443
511
  ticks_interval=intervalObj.get_data()
444
512
  if ticks_interval is None:
445
513
  return
514
+ #print('create_bar_with_last_and_ts', self.symbol, intervalId, len(ticks_interval))
446
515
  if len(ticks_interval)==0 or self._ts - ticks_interval[-1]['time'] >= intervalObj.delta:
447
516
  ticks_interval.append(new_item)
448
517
  current_bar = ticks_interval[-1]
@@ -457,6 +526,7 @@ class Ticker:
457
526
  current_bar['barcolor'] = self.red if current_bar['close'] <= current_bar['open'] else self.green
458
527
  #print(f'{self.symbol} {self._last}, {self._ts} {intervalId} {ticks_interval[-1]['time']} c' )
459
528
 
529
+ #print ('create_bar_with_last_and_ts', ticks_interval[-1])
460
530
  intervalObj.set_data(ticks_interval)
461
531
 
462
532
  except Exception as e:
@@ -560,24 +630,29 @@ class Tickers:
560
630
  # since the calulation is done at a different thread and uses a different memory space,
561
631
  # the caluated value has to be reassigned to the original ticker class instance from the caluated ticker instance
562
632
  def form_candle(self, tuples_list):
563
- with ProcessPoolExecutor() as executor:
564
- results = executor.map(self.process_ticker_candle, tuples_list, chunksize=10)
565
- for args, result in zip(tuples_list, results):
566
- for intervalId, interval in result[3].items():
567
- if not interval._data is None:
568
- args[0].get_interval_ticks(intervalId)._data = interval._data
569
- args[0].get_interval_ticks(intervalId).current_signal = interval.current_signal
570
- args[0].get_interval_ticks(intervalId).ema_open_signal = interval.ema_open_signal
571
- args[0].get_interval_ticks(intervalId).ema_close_signal = interval.ema_close_signal
572
- args[0].get_interval_ticks(intervalId).macd_signal = interval.macd_signal
573
- args[0].get_interval_ticks(intervalId).bbm_signal = interval.bbm_signal
574
- args[0].get_interval_ticks(intervalId).rsi_signal = interval.rsi_signal
575
- args[0].get_interval_ticks(intervalId).candle_trend = interval.candle_trend
576
- args[0].get_interval_ticks(intervalId).adx_signal = interval.adx_signal
577
- args[0].get_interval_ticks(intervalId).signal_strength = interval.signal_strength
578
- args[0]._last = result[0]
579
- args[0].lastcolor = result[1]
580
- args[0]._ts = result[2]
633
+ if not self.settings.CPU_PROCCESING:
634
+ for args in tuples_list:
635
+ ticker_obj, last, ts = args
636
+ result = self.process_ticker_candle(args)
637
+ else:
638
+ with ProcessPoolExecutor() as executor:
639
+ results = executor.map(self.process_ticker_candle, tuples_list, chunksize=10)
640
+ for args, result in zip(tuples_list, results):
641
+ for intervalId, interval in result[3].items():
642
+ if not interval._data is None:
643
+ args[0].get_interval_ticks(intervalId)._data = interval._data
644
+ args[0].get_interval_ticks(intervalId).current_signal = interval.current_signal
645
+ args[0].get_interval_ticks(intervalId).ema_open_signal = interval.ema_open_signal
646
+ args[0].get_interval_ticks(intervalId).ema_close_signal = interval.ema_close_signal
647
+ args[0].get_interval_ticks(intervalId).macd_signal = interval.macd_signal
648
+ args[0].get_interval_ticks(intervalId).bbm_signal = interval.bbm_signal
649
+ args[0].get_interval_ticks(intervalId).rsi_signal = interval.rsi_signal
650
+ args[0].get_interval_ticks(intervalId).candle_trend = interval.candle_trend
651
+ args[0].get_interval_ticks(intervalId).adx_signal = interval.adx_signal
652
+ args[0].get_interval_ticks(intervalId).signal_strength = interval.signal_strength
653
+ args[0]._last = result[0]
654
+ args[0].lastcolor = result[1]
655
+ args[0]._ts = result[2]
581
656
 
582
657
  def getCurrentData(self, period):
583
658
  current_data = []
@@ -596,33 +671,32 @@ class Tickers:
596
671
  ticks = intervalObj.get_data()
597
672
  if not ticks:
598
673
  continue
599
- if len(ticks)>=int(self.settings.BARS):
600
- lastcandle = intervalObj.get_data()[-1]
601
- if len(lastcandle) >= 20:
602
- new_row = {
603
- 'symbol' : symbol,
604
- f"{period}_trend": intervalObj.current_signal,
605
- f"{period}_cb": intervalObj.signal_strength,
606
- f"{period}_barcolor": lastcandle['barcolor'],
607
- f"{period}_ema_open": intervalObj.ema_open_signal,
608
- f"{period}_ema_close": intervalObj.ema_close_signal,
609
- f"{period}_macd":intervalObj.macd_signal,
610
- f"{period}_bbm":intervalObj.bbm_signal,
611
- f"{period}_rsi":intervalObj.rsi_signal,
612
- f"{period}_adx":intervalObj.adx_signal,
613
- f"{period}_candle_trend":intervalObj.candle_trend,
614
- 'bid' : bid,
615
- 'bidcolor' : bidcolor,
616
- 'last' : last,
617
- 'lastcolor' : lastcolor,
618
- 'ask' : ask,
619
- 'askcolor' : askcolor,
620
- f"{period}_open": lastcandle['open'],
621
- f"{period}_close": lastcandle['close'],
622
- f"{period}_high": lastcandle['high'],
623
- f"{period}_low": lastcandle['low'],
624
- }
625
- current_data.append(new_row)
674
+ lastcandle = intervalObj.get_data()[-1]
675
+ if len(lastcandle) >= 20:
676
+ new_row = {
677
+ 'symbol' : symbol,
678
+ f"{period}_trend": intervalObj.current_signal,
679
+ f"{period}_cb": intervalObj.signal_strength,
680
+ f"{period}_barcolor": lastcandle['barcolor'],
681
+ f"{period}_ema_open": intervalObj.ema_open_signal,
682
+ f"{period}_ema_close": intervalObj.ema_close_signal,
683
+ f"{period}_macd":intervalObj.macd_signal,
684
+ f"{period}_bbm":intervalObj.bbm_signal,
685
+ f"{period}_rsi":intervalObj.rsi_signal,
686
+ f"{period}_adx":intervalObj.adx_signal,
687
+ f"{period}_candle_trend":intervalObj.candle_trend,
688
+ 'bid' : bid,
689
+ 'bidcolor' : bidcolor,
690
+ 'last' : last,
691
+ 'lastcolor' : lastcolor,
692
+ 'ask' : ask,
693
+ 'askcolor' : askcolor,
694
+ f"{period}_open": lastcandle['open'],
695
+ f"{period}_close": lastcandle['close'],
696
+ f"{period}_high": lastcandle['high'],
697
+ f"{period}_low": lastcandle['low'],
698
+ }
699
+ current_data.append(new_row)
626
700
 
627
701
  df = pd.DataFrame(current_data)
628
702
  if not df.empty:
@@ -70,76 +70,6 @@ class bitunix():
70
70
  #create benchmark table
71
71
  self.cursor.execute("CREATE TABLE IF NOT EXISTS benchmark (id INTEGER PRIMARY KEY, process_name TEXT, time INTEGER)")
72
72
 
73
- #create settings table
74
- self.cursor.execute("CREATE TABLE IF NOT EXISTS settings (param TEXT PRIMARY KEY, value TEXT)")
75
- self.cursor.execute(f"SELECT param, value FROM settings")
76
- rows = self.cursor.fetchall()
77
- if len(rows) == 0:
78
- # fille value from confix.txt file to db
79
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("AUTOTRADE","True"))
80
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("OPTION_MOVING_AVERAGE","1h"))
81
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MAX_AUTO_TRADES","10"))
82
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("PROFIT_AMOUNT","3"))
83
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("LOSS_AMOUNT","0"))
84
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("LEVERAGE","20"))
85
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("THRESHOLD","5"))
86
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MIN_VOLUME","10000000"))
87
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("ORDER_AMOUNT_PERCENTAGE","5"))
88
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BARS","100"))
89
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MA_FAST","10"))
90
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MA_MEDIUM","20"))
91
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MA_SLOW","50"))
92
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("RSI_FAST","6"))
93
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("RSI_SLOW","24"))
94
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BBM_PERIOD","20"))
95
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BBM_STD","2"))
96
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MACD_PERIOD","9"))
97
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MACD_SHORT","12"))
98
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MACD_LONG","26"))
99
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("ADX_PERIOD","14"))
100
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("OPEN_ON_ANY_SIGNAL","True"))
101
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("EMA_STUDY","True"))
102
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("EMA_CHART","True"))
103
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("EMA_CROSSING","True"))
104
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("EMA_CHECK_ON_OPEN","True"))
105
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("EMA_CHECK_ON_CLOSE","True"))
106
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("EMA_CLOSE_ON_FAST_MEDIUM","True"))
107
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MACD_STUDY","True"))
108
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MACD_CHART","True"))
109
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MACD_CROSSING","True"))
110
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MACD_CHECK_ON_OPEN","True"))
111
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("MACD_CHECK_ON_CLOSE","True"))
112
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BBM_STUDY","True"))
113
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BBM_CHART","False"))
114
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BBM_CROSSING","False"))
115
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BBM_CHECK_ON_OPEN","False"))
116
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BBM_CHECK_ON_CLOSE","False"))
117
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("RSI_STUDY","True"))
118
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("RSI_CHART","True"))
119
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("RSI_CROSSING","False"))
120
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("RSI_CHECK_ON_OPEN","False"))
121
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("RSI_CHECK_ON_CLOSE","False"))
122
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("ADX_STUDY","True"))
123
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("ADX_CHECK_ON_OPEN","True"))
124
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("ADX_CHECK_ON_CLOSE","False"))
125
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("CANDLE_TREND_STUDY","False"))
126
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("CANDLE_TREND_CHECK_ON_OPEN","False"))
127
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("CANDLE_TREND_CHECK_ON_CLOSE","False"))
128
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("SCREEN_REFRESH_INTERVAL","1"))
129
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("SIGNAL_CHECK_INTERVAL","15"))
130
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("PORTFOLIO_API_INTERVAL","3"))
131
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("PENDING_POSITIONS_API_INTERVAL","3"))
132
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("PENDING_ORDERS_API_INTERVAL","3"))
133
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("TRADE_HISTORY_API_INTERVAL","3"))
134
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("POSITION_HISTORY_API_INTERVAL","3"))
135
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("TICKER_DATA_API_INTERVAL","120"))
136
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BATCH_PROCESS_SIZE","1000"))
137
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("USE_PUBLIC_WEBSOCKET","True"))
138
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("VERBOSE_LOGGING","False"))
139
- self.cursor.execute("INSERT INTO settings (param, value) VALUES (?, ?)", ("BENCHMARK","False"))
140
- self.connection.commit()
141
-
142
-
143
73
  async def update_settings(self, settings):
144
74
  self.settings = settings
145
75
  await self.bitunixSignal.update_settings(settings)
@@ -470,6 +400,8 @@ async def wscharts(websocket):
470
400
  "buysell": buysell,
471
401
  "ema_study": settings.EMA_STUDY,
472
402
  "ema_chart": settings.EMA_CHART,
403
+ "trendline_study": settings.TRENDLINE_STUDY,
404
+ "trendline_chart": settings.TRENDLINE_CHART,
473
405
  "macd_study": settings.MACD_STUDY,
474
406
  "macd_chart": settings.MACD_CHART,
475
407
  "bbm_study": settings.BBM_STUDY,
@@ -557,6 +489,8 @@ async def wschart(websocket):
557
489
  "period": period,
558
490
  "ema_study": settings.EMA_STUDY,
559
491
  "ema_chart": settings.EMA_CHART,
492
+ "trendline_study": settings.TRENDLINE_STUDY,
493
+ "trendline_chart": settings.TRENDLINE_CHART,
560
494
  "macd_study": settings.MACD_STUDY,
561
495
  "macd_chart": settings.MACD_CHART,
562
496
  "bbm_study": settings.BBM_STUDY,
@@ -59,6 +59,12 @@ class Settings(BaseSettings):
59
59
  RSI_CHECK_ON_OPEN: bool = Field(default=False)
60
60
  RSI_CHECK_ON_CLOSE: bool = Field(default=False)
61
61
 
62
+ TRENDLINE_CHART: bool = Field(default=True)
63
+ TRENDLINE_STUDY: bool = Field(default=True)
64
+ TRENDLINE_LOOKBACK: int = Field(default=20, ge=10, le=100)
65
+ TRENDLINE_CHECK_ON_OPEN: bool = Field(default=False)
66
+ TRENDLINE_CHECK_ON_CLOSE: bool = Field(default=False)
67
+
62
68
  ADX_STUDY: bool = Field(default=True)
63
69
  ADX_CHECK_ON_OPEN: bool = Field(default=False)
64
70
  ADX_CHECK_ON_CLOSE: bool = Field(default=False)
@@ -84,6 +90,9 @@ class Settings(BaseSettings):
84
90
  # Logger
85
91
  VERBOSE_LOGGING: bool = Field(default=False)
86
92
 
93
+ #use CPU
94
+ CPU_PROCCESING: bool = Field(default=True)
95
+
87
96
  # Benchmark
88
97
  BENCHMARK: bool = Field(default=False)
89
98
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bitunix_automated_crypto_trading
3
- Version: 3.1.2
3
+ Version: 3.1.3
4
4
  Summary: Bitunix Futures Auto Trading Platform
5
5
  Home-page: https://github.com/tcj2001/bitunix-automated-crypto-trading
6
6
  Author: tcj2001
@@ -0,0 +1,17 @@
1
+ bitunix_automated_crypto_trading/AsyncThreadRunner.py,sha256=LJ6ny1KSCVoIbfeNypsY4aHYcbkGME9M3epQ9e8B1O8,3224
2
+ bitunix_automated_crypto_trading/BitunixApi.py,sha256=W0uem1wIs1uM-jaGtXXzL_JQfnCDb7imyTZ2Tqjk8e8,11230
3
+ bitunix_automated_crypto_trading/BitunixSignal.py,sha256=17_VPwagjax-vFJ-A20cMApcyBtPCGdzis8EhAVoNrk,64734
4
+ bitunix_automated_crypto_trading/BitunixWebSocket.py,sha256=mbuvk8UFWKgv4KLV07TgLgxLVTRJnOKuf02mLB-VoCY,11143
5
+ bitunix_automated_crypto_trading/DataFrameHtmlRenderer.py,sha256=Pqdzhh_nfIxFEZH9L_R5QXB8moDPbgeTGT_hmBkHWMg,2899
6
+ bitunix_automated_crypto_trading/NotificationManager.py,sha256=pqDquEe-oujD2v8B543524vo62aRMjfB4YW-3DMhVGQ,795
7
+ bitunix_automated_crypto_trading/ThreadManager.py,sha256=WmYRQu8aNrgp5HwSqpBqX1WESNSEpbD2CznPFpd9HuI,2330
8
+ bitunix_automated_crypto_trading/TickerManager.py,sha256=W4UuW1RyU_4w_6IV0eDOlJ0PUFNorQOY9Ust4bI-69s,36785
9
+ bitunix_automated_crypto_trading/__init__.py,sha256=1hzk6nX8NnUCr1tsq8oFq1qGCNhNwnwldWE75641Eew,78
10
+ bitunix_automated_crypto_trading/bitunix.py,sha256=Zyrf8P-xi7DJogX_bcc6uDW66J7FAxdS-0jbuHRPFfM,25845
11
+ bitunix_automated_crypto_trading/config.py,sha256=Jj1AXFU9c3RHKRnxnAS7lJ6UIyfl6qRByoVbOVrEz1k,4857
12
+ bitunix_automated_crypto_trading/logger.py,sha256=tAaTQcv5r--zupk_Fhfe1USfBAzSiXzVa4QRnaOFIFY,2933
13
+ bitunix_automated_crypto_trading-3.1.3.dist-info/METADATA,sha256=UoUpv4RK83MLzcKnh8A6R3p0wltVYqLTQEpR6_ZzzCY,996
14
+ bitunix_automated_crypto_trading-3.1.3.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
15
+ bitunix_automated_crypto_trading-3.1.3.dist-info/entry_points.txt,sha256=UXREYHuSl2XYd_tOtLIq0zg3d1kX3lixX5SpN8yGBw4,82
16
+ bitunix_automated_crypto_trading-3.1.3.dist-info/top_level.txt,sha256=uyFzHUCOsp8elnG2Ovor6xXcf7dxRxY-C-Txiwix64Q,33
17
+ bitunix_automated_crypto_trading-3.1.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (79.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,17 +0,0 @@
1
- bitunix_automated_crypto_trading/AsyncThreadRunner.py,sha256=LJ6ny1KSCVoIbfeNypsY4aHYcbkGME9M3epQ9e8B1O8,3224
2
- bitunix_automated_crypto_trading/BitunixApi.py,sha256=gmhWi83k4EHOMIY7ZPa3x2NuIgVyzH13Sjk9AlVKjtQ,11163
3
- bitunix_automated_crypto_trading/BitunixSignal.py,sha256=z8-mvwZOR1VAAmrgy9HjgFyv-IRx1GxogcXjwCPJ4oY,64687
4
- bitunix_automated_crypto_trading/BitunixWebSocket.py,sha256=mbuvk8UFWKgv4KLV07TgLgxLVTRJnOKuf02mLB-VoCY,11143
5
- bitunix_automated_crypto_trading/DataFrameHtmlRenderer.py,sha256=Pqdzhh_nfIxFEZH9L_R5QXB8moDPbgeTGT_hmBkHWMg,2899
6
- bitunix_automated_crypto_trading/NotificationManager.py,sha256=pqDquEe-oujD2v8B543524vo62aRMjfB4YW-3DMhVGQ,795
7
- bitunix_automated_crypto_trading/ThreadManager.py,sha256=WmYRQu8aNrgp5HwSqpBqX1WESNSEpbD2CznPFpd9HuI,2330
8
- bitunix_automated_crypto_trading/TickerManager.py,sha256=g9Imr3uJijWeLqJbmCDrcDBwCHaBXV6P6sse73akmTA,33082
9
- bitunix_automated_crypto_trading/__init__.py,sha256=1hzk6nX8NnUCr1tsq8oFq1qGCNhNwnwldWE75641Eew,78
10
- bitunix_automated_crypto_trading/bitunix.py,sha256=c5vKRuN1-UaNz_ZB5Txu4-2UM6PsnRhs-ztvhRtpEzc,32779
11
- bitunix_automated_crypto_trading/config.py,sha256=QWAe5Ruq8A5anaFS-CamVm-3t1wMJjGG1DWaPIIWfiM,4521
12
- bitunix_automated_crypto_trading/logger.py,sha256=tAaTQcv5r--zupk_Fhfe1USfBAzSiXzVa4QRnaOFIFY,2933
13
- bitunix_automated_crypto_trading-3.1.2.dist-info/METADATA,sha256=5hhgVdOaJ-kqG0zdmen-OXVGpvBtXJxXjoU-tg_8-WI,996
14
- bitunix_automated_crypto_trading-3.1.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
15
- bitunix_automated_crypto_trading-3.1.2.dist-info/entry_points.txt,sha256=UXREYHuSl2XYd_tOtLIq0zg3d1kX3lixX5SpN8yGBw4,82
16
- bitunix_automated_crypto_trading-3.1.2.dist-info/top_level.txt,sha256=uyFzHUCOsp8elnG2Ovor6xXcf7dxRxY-C-Txiwix64Q,33
17
- bitunix_automated_crypto_trading-3.1.2.dist-info/RECORD,,