bitunix-automated-crypto-trading 3.1.6__py3-none-any.whl → 3.1.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,7 @@
1
1
  import pandas as pd
2
2
  import numpy as np
3
3
  from scipy.signal import find_peaks
4
-
5
- class SupportResistance:
6
- import pandas as pd
7
- import numpy as np
4
+ import talib
8
5
 
9
6
  class SupportResistance:
10
7
  def _find_peaks(self, prices, prominence=None, distance=None):
@@ -33,7 +30,7 @@ class SupportResistance:
33
30
  intercept = price1 - slope * index1
34
31
  return slope * np.arange(length) + intercept
35
32
 
36
- def support_resistance_trend_lines(self, data, lookback=20, prominence=None, distance=None):
33
+ def support_resistance_trend_lines(self, data, lookback=24, prominence=None, distance=None):
37
34
  if data is None or len(data) < lookback:
38
35
  return pd.DataFrame()
39
36
  try:
@@ -44,39 +41,69 @@ class SupportResistance:
44
41
 
45
42
  # Find all local peaks and troughs
46
43
  peak_indices_all = self._find_peaks(high_prices, prominence=prominence, distance=distance)
47
- if len(peak_indices_all) > 0 and peak_indices_all[-1] < lookback - 2 and high_prices[-2] > high_prices[lookback - peak_indices_all[-1]]:
48
- peak_indices_all = np.append(peak_indices_all,lookback - 2)
49
44
  trough_indices_all = self._find_troughs(low_prices, prominence=prominence, distance=distance)
50
- if len(trough_indices_all) > 0 and trough_indices_all[-1] < lookback - 2 and low_prices[-2] < low_prices[lookback - trough_indices_all[-1]]:
51
- trough_indices_all = np.append(trough_indices_all, lookback - 2)
52
- # Get the two most recent prominent peaks
53
- most_recent_peaks_indices = self._get_n_most_recent_prominent(peak_indices_all, high_prices, n=2)
54
-
55
- # Get the two most recent prominent troughs
56
- most_recent_troughs_indices = self._get_n_most_recent_prominent(trough_indices_all, low_prices, n=2)
57
45
 
58
46
  support_line = np.full(lookback, np.nan)
59
47
  resistance_line = np.full(lookback, np.nan)
60
48
 
61
- if len(most_recent_peaks_indices) >= 2:
62
- # Sort by index (time) to ensure correct order
63
- sorted_peak_indices = most_recent_peaks_indices #np.sort(most_recent_peaks_indices)
64
- resistance_line_full = self._get_line(sorted_peak_indices[0], high_prices[sorted_peak_indices[0]],
65
- sorted_peak_indices[1], high_prices[sorted_peak_indices[1]], lookback)
66
- # Set values before the second peak to NaN
67
- resistance_line[sorted_peak_indices[1]:] = resistance_line_full[sorted_peak_indices[1]:]
68
- elif len(most_recent_peaks_indices) == 1:
69
- resistance_line[most_recent_peaks_indices[0]:] = high_prices[most_recent_peaks_indices[0]] # Horizontal line from the peak onwards
70
-
71
- if len(most_recent_troughs_indices) >= 2:
72
- # Sort by index (time) to ensure correct order
73
- sorted_trough_indices = most_recent_troughs_indices #np.sort(most_recent_troughs_indices)
74
- support_line_full = self._get_line(sorted_trough_indices[0], low_prices[sorted_trough_indices[0]],
75
- sorted_trough_indices[1], low_prices[sorted_trough_indices[1]], lookback)
76
- # Set values before the second trough to NaN
77
- support_line[sorted_trough_indices[1]:] = support_line_full[sorted_trough_indices[1]:]
78
- elif len(most_recent_troughs_indices) == 1:
79
- support_line[most_recent_troughs_indices[0]:] = low_prices[most_recent_troughs_indices[0]] # Horizontal line from the trough onwards
49
+ if len(peak_indices_all) > 0:
50
+ if len(peak_indices_all) >= 2:
51
+ resistance_line_full = self._get_line(peak_indices_all[-1], high_prices[peak_indices_all[-1]],
52
+ peak_indices_all[-2], high_prices[peak_indices_all[-2]], lookback)
53
+ # Set values before the second peak to NaN
54
+ resistance_line[peak_indices_all[-2]:] = resistance_line_full[peak_indices_all[-2]:]
55
+ elif len(peak_indices_all) == 1:
56
+ resistance_line[peak_indices_all[-1]:] = high_prices[peak_indices_all[-1]] # Horizontal line from the peak onwards
57
+
58
+ if len(trough_indices_all) > 0:
59
+ if len(trough_indices_all) >= 2:
60
+ support_line_full = self._get_line(trough_indices_all[-1], low_prices[trough_indices_all[-1]],
61
+ trough_indices_all[-2], low_prices[trough_indices_all[-2]], lookback)
62
+ # Set values before the second trough to NaN
63
+ support_line[trough_indices_all[-2]:] = support_line_full[trough_indices_all[-2]:]
64
+ elif len(trough_indices_all) == 1:
65
+ support_line[trough_indices_all[-1]:] = low_prices[trough_indices_all[-1]] # Horizontal line from the trough onwards
66
+
67
+ results_df = pd.DataFrame({
68
+ 'time': ts,
69
+ 'support_line': support_line,
70
+ 'resistance_line': resistance_line
71
+ })
72
+ return results_df
73
+ except Exception as e:
74
+ print(f"trendline error occurred: {e}")
75
+ return pd.DataFrame()
76
+
77
+ def support_resistance_bos_lines(self, data, length, lookback=24):
78
+ if data is None or len(data) < lookback:
79
+ return pd.DataFrame()
80
+ try:
81
+ recent_data = data.iloc[-length:].copy()
82
+ highs = recent_data['high'].values
83
+ high_prices = np.full_like(highs, np.nan, dtype=np.float64)
84
+ high_prices[-lookback:] = highs[-lookback:]
85
+
86
+ lows = recent_data['low'].values
87
+ low_prices = np.full_like(lows, np.nan, dtype=np.float64)
88
+ low_prices[-lookback:] = lows[-lookback:]
89
+
90
+ ts = recent_data['time'].values
91
+
92
+ support_line = np.full(length, np.nan)
93
+ resistance_line = np.full(length, np.nan)
94
+
95
+ # Find all local peaks and troughs and its highest and lowest values
96
+ peak_indices_all = self._find_peaks(high_prices)
97
+ if len(peak_indices_all) == 0:
98
+ highest_peak_index = peak_indices_all[np.argmax(high_prices[peak_indices_all])]
99
+ highest_peak_value = high_prices[highest_peak_index]
100
+ resistance_line[highest_peak_index:] = high_prices[highest_peak_index] # Horizontal line from the highest point onwards
101
+
102
+ trough_indices_all = self._find_troughs(low_prices)
103
+ if len(trough_indices_all) == 0:
104
+ lowest_peak_index = trough_indices_all[np.argmin(low_prices[trough_indices_all])]
105
+ lowest_peak_value = low_prices[lowest_peak_index]
106
+ support_line[lowest_peak_index:] = low_prices[lowest_peak_index] # Horizontal line from the lowset point onwards
80
107
 
81
108
  results_df = pd.DataFrame({
82
109
  'time': ts,
@@ -85,5 +112,6 @@ class SupportResistance:
85
112
  })
86
113
  return results_df
87
114
  except Exception as e:
88
- print(f"An error occurred: {e}")
89
- return pd.DataFrame()
115
+ print(f"bos error occurred: {e}")
116
+ return pd.DataFrame()
117
+
@@ -10,7 +10,7 @@
10
10
  import time
11
11
  import threading
12
12
  from logger import Logger
13
- logger = Logger(__name__).get_logger()
13
+ global LOG_FILE
14
14
 
15
15
  def job_func(*args, **kwargs):
16
16
  print(f"Job running with arguments: {args}, {kwargs}")
@@ -20,13 +20,14 @@ def run_threaded(job_func, args):
20
20
  job_thread.start()
21
21
 
22
22
  class ManagedThread(threading.Thread):
23
- def __init__(self, interval, target, *args, **kwargs):
23
+ def __init__(self, interval, target, logger, *args, **kwargs):
24
24
  super().__init__()
25
25
  self.target = target
26
26
  self.interval = interval
27
27
  self.args = args
28
28
  self.kwargs = kwargs
29
29
  self._stop_event = threading.Event()
30
+ self.logger = logger
30
31
 
31
32
  def run(self):
32
33
  while not self._stop_event.is_set():
@@ -34,7 +35,7 @@ class ManagedThread(threading.Thread):
34
35
  try:
35
36
  self.target(self, *self.args, **self.kwargs)
36
37
  except Exception as e:
37
- logger.info(f"error in thread {self.name}, {e}, {e.args}, {type(e).__name__}")
38
+ self.logger.info(f"error in thread {self.name}, {e}, {e.args}, {type(e).__name__}")
38
39
  elapsed_time = time.time() - stime
39
40
  if self.interval==0:
40
41
  break
@@ -7,25 +7,27 @@ import asyncio
7
7
  import talib
8
8
  import traceback
9
9
  from logger import Logger
10
- logger = Logger(__name__).get_logger()
11
10
  import gc
12
11
  from concurrent.futures import ProcessPoolExecutor
13
12
  from SupportResistance import SupportResistance
14
13
  sr = SupportResistance()
15
14
 
16
15
  class Interval:
17
- def __init__(self, symbol, intervalId, delta, data, settings):
16
+ def __init__(self, symbol, intervalId, delta, data, settings, logger):
18
17
  self.symbol = symbol
19
18
  self.intervalId = intervalId
20
19
  self.delta = delta
21
20
  self.settings=settings
22
21
  self._data = data
22
+ self.logger = logger
23
+
23
24
 
24
25
  #these signals are used to list stocks in the signals sections on the main page
25
26
  self.current_signal="HOLD"
26
27
  self.ema_open_signal="HOLD"
27
28
  self.ema_close_signal="HOLD"
28
29
  self.trendline_signal = "HOLD"
30
+ self.bos_signal = "HOLD"
29
31
  self.macd_signal="HOLD"
30
32
  self.bbm_signal="HOLD"
31
33
  self.rsi_signal="HOLD"
@@ -63,20 +65,6 @@ class Interval:
63
65
  # Get the last color and its consecutive count
64
66
  self.signal_strength = df['Consecutive'].iloc[-1]
65
67
 
66
- # Break of Strcuture
67
- if self.settings.BOS_STUDY:
68
- high = df.iloc[:-1]['high'].max()
69
- low = df.iloc[:-1]['low'].min()
70
- close = df['close'].iloc[-1]
71
- if close > high:
72
- self.bos_signal = "BUY"
73
- elif close < low:
74
- self.bos_signal = "SELL"
75
- else:
76
- self.bos_signal = "HOLD"
77
- else:
78
- self.bos_signal = "HOLD"
79
-
80
68
  # Calculate the Moving Averages
81
69
  if self.settings.EMA_STUDY:
82
70
  df['ma_fast'] = talib.EMA(df['close'], timeperiod=self.settings.MA_FAST)
@@ -245,27 +233,47 @@ class Interval:
245
233
  # Drop RSI columns if not used
246
234
  df.drop(['rsi_fast', 'rsi_slow', 'rsi_slope', 'rsi_angle'], axis=1, inplace=True, errors='ignore')
247
235
 
236
+ # Break of Strcuture
237
+ if self.settings.BOS_STUDY:
238
+ df_sr= sr.support_resistance_bos_lines(df[['time','open', 'high', 'low', 'close']], len(df), self.settings.BOS_PERIOD)
239
+ if df_sr is not None and len(df_sr) >= 1:
240
+ df['bos_support_line'] = df_sr['support_line']
241
+ df['bos_resistance_line'] = df_sr['resistance_line']
242
+ df.fillna({'bos_support_line':0}, inplace=True)
243
+ df.fillna({'bos_resistance_line':0}, inplace=True)
244
+
245
+ if df['high'].size > 1 and df['low'].size > 1 and df['close'].size > 1:
246
+ if df['close'].iloc[-1] > df['bos_resistance_line'].iloc[-1]:
247
+ self.bos_signal = "BUY"
248
+ elif df['close'].iloc[-1] < df['bos_support_line'].iloc[-1]:
249
+ self.bos_signal = "SELL"
250
+ else:
251
+ self.bos_signal = "HOLD"
252
+ else:
253
+ self.bos_signal = "HOLD"
254
+
248
255
  #Trendline
249
256
  if self.settings.TRENDLINE_STUDY:
250
257
  loopback = len(df)
251
258
  df_sr= sr.support_resistance_trend_lines(df[['time','open', 'high', 'low', 'close']], loopback, prominence=None, distance=None if self.settings.TRENDLINE_PEAK_DISTANCE==0 else self.settings.TRENDLINE_PEAK_DISTANCE)
252
259
  if df_sr is not None and len(df_sr) >= 1:
253
- df['support_line'] = df_sr['support_line']
254
- df['resistance_line'] = df_sr['resistance_line']
255
- df.fillna({'support_line':0}, inplace=True)
256
- df.fillna({'resistance_line':0}, inplace=True)
260
+ df['trend_support_line'] = df_sr['support_line']
261
+ df['trend_resistance_line'] = df_sr['resistance_line']
262
+ df.fillna({'trend_support_line':0}, inplace=True)
263
+ df.fillna({'trend_resistance_line':0}, inplace=True)
264
+
257
265
  if df is not None and len(df) >= 2:
258
266
  if self.settings.TRENDLINE_BREAKOUT:
259
- if df['close'].iloc[-2] > df['support_line'].iloc[-2] and df['open'].iloc[-1] > df['support_line'].iloc[-1] and df['close'].iloc[-1] > df['open'].iloc[-1]:
267
+ if df['close'].iloc[-1] > df['trend_resistance_line'].iloc[-1]:
260
268
  self.trendline_signal = "BUY"
261
- elif df['close'].iloc[-2] < df['resistance_line'].iloc[-2] and df['open'].iloc[-1] < df['resistance_line'].iloc[-1] and df['close'].iloc[-1] < df['open'].iloc[-1]:
269
+ elif df['close'].iloc[-1] < df['trend_support_line'].iloc[-1]:
262
270
  self.trendline_signal = "SELL"
263
271
  else:
264
272
  self.trendline_signal = "HOLD"
265
273
  else:
266
- if df['high'].iloc[-3] >= df['support_line'].iloc[-3] and df['close'].iloc[-2] < df['support_line'].iloc[-2] and df['close'].iloc[-1] < df['open'].iloc[-1]:
274
+ if df['close'].iloc[-1] < df['trend_resistance_line'].iloc[-1] and df['close'].iloc[-2] < df['open'].iloc[-2] and df['close'].iloc[-1] < df['open'].iloc[-1]:
267
275
  self.trendline_signal = "SELL"
268
- elif df['low'].iloc[-3] <= df['resistance_line'].iloc[-3] and df['close'].iloc[-2] > df['resistance_line'].iloc[-2] and df['close'].iloc[-1] > df['open'].iloc[-1]:
276
+ elif df['close'].iloc[-1] > df['trend_support_line'].iloc[-1] and df['close'].iloc[-2] > df['open'].iloc[-2] and df['close'].iloc[-1] > df['open'].iloc[-1]:
269
277
  self.trendline_signal = "BUY"
270
278
  else:
271
279
  self.trendline_signal = "HOLD"
@@ -314,7 +322,7 @@ class Interval:
314
322
 
315
323
  # Check for BUY signal
316
324
  buy_conditions = (
317
- (self.settings.BOS_STUDY and self.bos_signal == "BUY") or
325
+ (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "BUY") or
318
326
  (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "BUY") or
319
327
  (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_OPEN and self.macd_signal == "BUY") or
320
328
  (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_OPEN and self.bbm_signal == "BUY") or
@@ -328,7 +336,7 @@ class Interval:
328
336
 
329
337
  # Check for SELL signal
330
338
  sell_conditions = (
331
- (self.settings.BOS_STUDY and self.bos_signal == "SELL") or
339
+ (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "SELL") or
332
340
  (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "SELL") or
333
341
  (self.settings.MACD_STUDY and self.settings.MACD_CHECK_ON_OPEN and self.macd_signal == "SELL") or
334
342
  (self.settings.BBM_STUDY and self.settings.BBM_CHECK_ON_OPEN and self.bbm_signal == "SELL") or
@@ -349,7 +357,7 @@ class Interval:
349
357
  self.current_signal = "HOLD"
350
358
  else:
351
359
  buy_conditions = (
352
- (self.settings.BOS_STUDY and self.bos_signal == "BUY")
360
+ (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "BUY")
353
361
  or not self.settings.BOS_STUDY
354
362
  ) and (
355
363
  (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "BUY")
@@ -383,7 +391,7 @@ class Interval:
383
391
 
384
392
  # Check for SELL signal
385
393
  sell_conditions = (
386
- (self.settings.BOS_STUDY and self.bos_signal == "SELL")
394
+ (self.settings.BOS_STUDY and self.settings.BOS_CHECK_ON_OPEN and self.bos_signal == "SELL")
387
395
  or not self.settings.BOS_STUDY
388
396
  ) and (
389
397
  (self.settings.EMA_STUDY and self.settings.EMA_CHECK_ON_OPEN and self.ema_open_signal == "SELL")
@@ -425,8 +433,8 @@ class Interval:
425
433
 
426
434
 
427
435
  except Exception as e:
428
- logger.info(f"Function: calculate_study, {e}, {e.args}, {type(e).__name__}")
429
- logger.info(traceback.print_exc())
436
+ self.logger.info(f"Function: calculate_study, {e}, {e.args}, {type(e).__name__}")
437
+ self.logger.info(traceback.print_exc())
430
438
  retval = df.to_dict('records')
431
439
  del df
432
440
  gc.collect()
@@ -434,10 +442,10 @@ class Interval:
434
442
 
435
443
  class Ticker:
436
444
 
437
- def __init__(self, symbol, intervalIds, settings):
445
+ def __init__(self, symbol, intervalIds, settings, logger):
438
446
  self.symbol=symbol
439
447
  self.settings=settings
440
-
448
+ self.logger=logger
441
449
  self._ts=0
442
450
  self._bid = 0.0
443
451
  self.bidcolor = ""
@@ -448,11 +456,11 @@ class Ticker:
448
456
  self._mtv=0.0
449
457
  self.intervalIds=intervalIds
450
458
  self._intervals = {
451
- '1m' : Interval(self.symbol, '1m', 60000, [], self.settings),
452
- '5m' : Interval(self.symbol, '5m', 300000, [], self.settings),
453
- '15m': Interval(self.symbol, '15m', 900000, [], self.settings),
454
- '1h' : Interval(self.symbol, '1h', 3600000, [], self.settings),
455
- '1d' : Interval(self.symbol, '1d', 86400000, [], self.settings),
459
+ '1m' : Interval(self.symbol, '1m', 60000, [], self.settings, self.logger),
460
+ '5m' : Interval(self.symbol, '5m', 300000, [], self.settings, self.logger),
461
+ '15m': Interval(self.symbol, '15m', 900000, [], self.settings, self.logger),
462
+ '1h' : Interval(self.symbol, '1h', 3600000, [], self.settings, self.logger),
463
+ '1d' : Interval(self.symbol, '1d', 86400000, [], self.settings, self.logger),
456
464
  }
457
465
  self.current_data={}
458
466
  self.trades = []
@@ -460,6 +468,8 @@ class Ticker:
460
468
  self.green="#A5DFDF"
461
469
  self.red="#FFB1C1"
462
470
 
471
+ self.logger = logger
472
+
463
473
  def update_settings(self, settings):
464
474
  self.settings=settings
465
475
  for intervalId in self.intervalIds:
@@ -577,12 +587,12 @@ class Ticker:
577
587
  intervalObj.set_data(ticks_interval)
578
588
 
579
589
  except Exception as e:
580
- logger.info(f"Function: create_bar_with_last_and_ts, {e}, {e.args}, {type(e).__name__}")
581
- logger.info(traceback.print_exc())
590
+ self.logger.info(f"Function: create_bar_with_last_and_ts, {e}, {e.args}, {type(e).__name__}")
591
+ self.logger.info(traceback.print_exc())
582
592
 
583
593
 
584
594
  class Tickers:
585
- def __init__(self, settings):
595
+ def __init__(self, settings, logger):
586
596
  self.settings=settings
587
597
 
588
598
  self._tickerObjects={}
@@ -595,13 +605,15 @@ class Tickers:
595
605
 
596
606
  self.intervalIds=['1m','5m','15m','1h','1d']
597
607
 
608
+ self.logger = logger
609
+
598
610
  def update_settings(self, settings):
599
611
  self.settings=settings
600
612
  for symbol in self._tickerObjects:
601
613
  self._tickerObjects[symbol].update_settings(settings)
602
614
 
603
615
  def add(self, symbol):
604
- ticker = Ticker(symbol, self.intervalIds, self.settings)
616
+ ticker = Ticker(symbol, self.intervalIds, self.settings, self.logger)
605
617
  self._tickerObjects[symbol]=ticker
606
618
 
607
619
  def get_tickerDict(self):
@@ -727,13 +739,13 @@ class Tickers:
727
739
  f"{period}_trend": intervalObj.current_signal,
728
740
  f"{period}_cb": intervalObj.signal_strength,
729
741
  f"{period}_barcolor": lastcandle['barcolor'],
730
- f"{period}_bos": intervalObj.bos_signal,
731
742
  f"{period}_ema_open": intervalObj.ema_open_signal,
732
743
  f"{period}_ema_open": intervalObj.ema_open_signal,
733
744
  f"{period}_ema_close": intervalObj.ema_close_signal,
734
745
  f"{period}_macd":intervalObj.macd_signal,
735
746
  f"{period}_bbm":intervalObj.bbm_signal,
736
747
  f"{period}_rsi":intervalObj.rsi_signal,
748
+ f"{period}_bos": intervalObj.bos_signal,
737
749
  f"{period}_trendline": intervalObj.trendline_signal,
738
750
  f"{period}_adx":intervalObj.adx_signal,
739
751
  f"{period}_candle_trend":intervalObj.candle_trend,
@@ -779,8 +791,8 @@ class Tickers:
779
791
  ]
780
792
  self.signaldf_filtered = df[np.any(trending_conditions, axis=0)].copy()
781
793
  except Exception as e:
782
- logger.info(f"Function: getCurrentData, {e}, {e.args}, {type(e).__name__}")
783
- logger.info(traceback.print_exc())
794
+ self.logger.info(f"Function: getCurrentData, {e}, {e.args}, {type(e).__name__}")
795
+ self.logger.info(traceback.print_exc())
784
796
  finally:
785
797
  del df, current_data
786
798
  gc.collect()
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  import os
3
+ import sys
3
4
  import uvicorn
4
5
  import numpy as np
5
6
  import pandas as pd
@@ -17,7 +18,6 @@ from NotificationManager import NotificationManager
17
18
  from DataFrameHtmlRenderer import DataFrameHtmlRenderer
18
19
  from config import Settings
19
20
  from logger import Logger
20
- logger = Logger(__name__).get_logger()
21
21
 
22
22
  from fastapi import FastAPI, Request, Form, WebSocket, WebSocketDisconnect, Depends, Query
23
23
  from fastapi.responses import HTMLResponse , JSONResponse, RedirectResponse, StreamingResponse
@@ -34,9 +34,24 @@ from pydantic import ValidationError
34
34
 
35
35
  import sqlite3
36
36
 
37
- ENV_FILE = ".env"
38
- CONFIG_FILE = os.path.dirname(os.path.abspath(__file__))+"/config.txt"
39
- LOG_FILE = "app.log"
37
+
38
+ global LOG_FILE
39
+ global ENV_FILE
40
+ global CONFIG_FILE
41
+ global API_KEY
42
+ global SECRET_KEY
43
+ global SECRET
44
+ global PASSWORD
45
+ global HOST
46
+ global port
47
+
48
+ env_file = sys.argv[1] if len(sys.argv) > 1 else ".env"
49
+ config_file=sys.argv[2] if len(sys.argv) > 2 else "config.txt"
50
+ port = sys.argv[3] if len(sys.argv) > 3 else "8000"
51
+
52
+ ENV_FILE = os.path.dirname(os.path.abspath(__file__))+"/"+env_file
53
+ CONFIG_FILE = os.path.dirname(os.path.abspath(__file__))+"/"+config_file
54
+ LOG_FILE = os.path.dirname(os.path.abspath(__file__))+"/"+config_file.replace(".txt", ".log")
40
55
 
41
56
  #load environment variables
42
57
  load_dotenv(ENV_FILE)
@@ -46,23 +61,24 @@ SECRET = os.getenv('SECRET')
46
61
  PASSWORD = os.getenv('PASSWORD')
47
62
  HOST = os.getenv('HOST')
48
63
 
49
- #load config variables using setting class in config.py validating using pydantic
50
- settings = Settings()
64
+ logger = Logger(__name__, LOG_FILE).get_logger()
65
+
66
+ #logger.info(f"secret: {SECRET}, api_key: {API_KEY}, secret_key: {SECRET_KEY}, password: {PASSWORD}, host: {HOST}, port: {port}, config_file: {config_file}")
51
67
 
52
68
  class bitunix():
53
- def __init__(self, password, api_key, secret_key, settings):
69
+ def __init__(self, password, api_key, secret_key, settings, logger):
54
70
  self.screen_refresh_interval =settings.SCREEN_REFRESH_INTERVAL
55
-
71
+ self.logger=logger
56
72
  self.autoTrade=settings.AUTOTRADE
57
73
 
58
74
  self.threadManager = ThreadManager()
59
- self.notifications = NotificationManager()
60
- self.bitunixApi = BitunixApi(api_key, secret_key, settings)
61
- self.bitunixSignal = BitunixSignal(api_key, secret_key, settings, self.threadManager, self.notifications, self.bitunixApi)
75
+ self.notifications = NotificationManager(logger)
76
+ self.bitunixApi = BitunixApi(api_key, secret_key, settings, self.logger)
77
+ self.bitunixSignal = BitunixSignal(api_key, secret_key, settings, self.threadManager, self.notifications, self.bitunixApi, self.logger)
62
78
 
63
79
  self.websocket_connections = set()
64
80
  self.DB = {"admin": {"password": password}}
65
-
81
+
66
82
  #sqllite database connection
67
83
  self.connection = sqlite3.connect("bitunix.db")
68
84
  #create table if not exist
@@ -104,7 +120,7 @@ app.add_middleware(
104
120
  allow_headers=["*"],
105
121
  )
106
122
  templates = Jinja2Templates(directory=os.path.dirname(os.path.abspath(__file__))+"/templates")
107
- SECRET=os.getenv('SECRET')
123
+ #SECRET=os.getenv('SECRET')
108
124
  login_manager = LoginManager(SECRET, token_url="/auth/login", use_cookie=True)
109
125
  login_manager.cookie_name = "auth_token"
110
126
 
@@ -242,6 +258,7 @@ async def wsmain(websocket):
242
258
  "profit" : bitunix.bitunixSignal.profit,
243
259
  "atctime": atctime,
244
260
  "tdctime": tdctime,
261
+ "port" : port,
245
262
  "status_messages": [] if len(notifications)==0 else notifications
246
263
  }
247
264
 
@@ -402,6 +419,8 @@ async def wscharts(websocket):
402
419
  "ema_chart": settings.EMA_CHART,
403
420
  "trendline_study": settings.TRENDLINE_STUDY,
404
421
  "trendline_chart": settings.TRENDLINE_CHART,
422
+ "bos_study": settings.BOS_STUDY,
423
+ "bos_chart": settings.BOS_CHART,
405
424
  "macd_study": settings.MACD_STUDY,
406
425
  "macd_chart": settings.MACD_CHART,
407
426
  "bbm_study": settings.BBM_STUDY,
@@ -491,6 +510,8 @@ async def wschart(websocket):
491
510
  "ema_chart": settings.EMA_CHART,
492
511
  "trendline_study": settings.TRENDLINE_STUDY,
493
512
  "trendline_chart": settings.TRENDLINE_CHART,
513
+ "bos_study": settings.BOS_STUDY,
514
+ "bos_chart": settings.BOS_CHART,
494
515
  "macd_study": settings.MACD_STUDY,
495
516
  "macd_chart": settings.MACD_CHART,
496
517
  "bbm_study": settings.BBM_STUDY,
@@ -604,14 +625,19 @@ async def stream_log_file(websocket: WebSocket):
604
625
 
605
626
  def main():
606
627
  global bitunix
607
- bitunix = bitunix(PASSWORD, API_KEY, SECRET_KEY, settings)
608
- bitunix.bitunixSignal.notifications.add_notification(f"Starting....................")
628
+ global settings
629
+
630
+ #load config variables using setting class in config.py validating using pydantic
631
+ settings = Settings()
632
+
633
+ bitunix = bitunix(PASSWORD, API_KEY, SECRET_KEY, settings, logger)
634
+ bitunix.bitunixSignal.notifications.add_notification(f"Starting auto trade on port {port} using {env_file} and {config_file} ....................")
609
635
  import uvicorn
610
636
  if settings.VERBOSE_LOGGING:
611
637
  llevel = "debug"
612
638
  else:
613
639
  llevel = "error"
614
- config1 = uvicorn.Config(app, host=HOST, port=8000, log_level=llevel, reload=False)
640
+ config1 = uvicorn.Config(app, host=HOST, port=port, log_level=llevel, reload=False)
615
641
  server = uvicorn.Server(config1)
616
642
  server.run()
617
643
 
@@ -1,6 +1,7 @@
1
1
  from pydantic import Field, SecretStr, validator
2
2
  from pydantic_settings import BaseSettings
3
3
  import os
4
+ import sys
4
5
  import sqlite3
5
6
 
6
7
  class Settings(BaseSettings):
@@ -37,7 +38,12 @@ class Settings(BaseSettings):
37
38
  # Technical Indicators
38
39
  OPEN_ON_ANY_SIGNAL: bool = Field(default=True)
39
40
 
41
+ BOS_PERIOD: int = Field(default=20, ge=1)
40
42
  BOS_STUDY: bool = Field(default=True)
43
+ BOS_CHART: bool = Field(default=True)
44
+ BOS_CHECK_ON_OPEN: bool = Field(default=False)
45
+ BOS_CHECK_ON_CLOSE: bool = Field(default=False)
46
+
41
47
  EMA_CHART: bool = Field(default=True)
42
48
  EMA_STUDY: bool = Field(default=True)
43
49
  EMA_CROSSING: bool = Field(default=False)
@@ -103,7 +109,8 @@ class Settings(BaseSettings):
103
109
 
104
110
  class Config:
105
111
  # Specify the file name for loading environment variables
106
- env_file = os.path.dirname(os.path.abspath(__file__))+"/config.txt"
112
+ config_file=sys.argv[2] if len(sys.argv) > 1 else "config.txt"
113
+ env_file = os.path.dirname(os.path.abspath(__file__))+"/"+config_file
107
114
 
108
115
 
109
116
  @classmethod
@@ -45,7 +45,7 @@ class CSTFormatter(logging.Formatter):
45
45
  return cst_time.isoformat()
46
46
 
47
47
  class Logger:
48
- def __init__(self, logger_name, log_file='app.log', level=logging.DEBUG, max_bytes=50 * 1024 * 1024, backup_count=100):
48
+ def __init__(self, logger_name, log_file, level=logging.DEBUG, max_bytes=50 * 1024 * 1024, backup_count=100):
49
49
  """
50
50
  Initialize the logger.
51
51
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bitunix_automated_crypto_trading
3
- Version: 3.1.6
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
@@ -0,0 +1,18 @@
1
+ bitunix_automated_crypto_trading/AsyncThreadRunner.py,sha256=bNIM_1xRYQOFEsIn74EX6qVpC59-GMhhr2CeiPr_GWg,3253
2
+ bitunix_automated_crypto_trading/BitunixApi.py,sha256=udgBwbWowf7v46jVVyfs-VjeNh9ajnghTiJf70lvn5w,11269
3
+ bitunix_automated_crypto_trading/BitunixSignal.py,sha256=hZvu1FKhdHqESIUmDMMlVdnxsROnJHTMCfGSitrXNiM,70882
4
+ bitunix_automated_crypto_trading/BitunixWebSocket.py,sha256=-_7wRAZxJXG63joBq2k3TUC4qd06v7Miki-LGVtNIDk,11234
5
+ bitunix_automated_crypto_trading/DataFrameHtmlRenderer.py,sha256=Pqdzhh_nfIxFEZH9L_R5QXB8moDPbgeTGT_hmBkHWMg,2899
6
+ bitunix_automated_crypto_trading/NotificationManager.py,sha256=exs6REABBA1omTeTGuUuECzxs5dGqdyL7oI8WyxS6Xc,798
7
+ bitunix_automated_crypto_trading/SupportResistance.py,sha256=_aP9G_DQ16bHqZv8HdxIairqeZzqB8ipRUhBPijN7lk,5767
8
+ bitunix_automated_crypto_trading/ThreadManager.py,sha256=Lw5_1EIT0m3AFSv5CIMpnjtA0DnNw2qQ6JtSpT34LyM,2349
9
+ bitunix_automated_crypto_trading/TickerManager.py,sha256=B9HlgvBLIZ2skBCEojY0M0BS5ZvZR2rw4l25LhuTt1o,42307
10
+ bitunix_automated_crypto_trading/__init__.py,sha256=1hzk6nX8NnUCr1tsq8oFq1qGCNhNwnwldWE75641Eew,78
11
+ bitunix_automated_crypto_trading/bitunix.py,sha256=wEzJpa1Gv84tYJK1iV-kQVezbn1TxJuAk-CY7kwKShM,26887
12
+ bitunix_automated_crypto_trading/config.py,sha256=cdbPFRNbDPw2mxEKL4asffVtfUcq_zM0zTVqY0o3Hg4,5300
13
+ bitunix_automated_crypto_trading/logger.py,sha256=NHnA5JZdUFkTAhB7i-1iCAwrdf1fxhDuRvJUkbKPi9Y,2923
14
+ bitunix_automated_crypto_trading-3.1.8.dist-info/METADATA,sha256=pMRfJvAcx91aQ8_8ltWv8Uo2IGn5s1nGBOQmdkgH-3U,996
15
+ bitunix_automated_crypto_trading-3.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ bitunix_automated_crypto_trading-3.1.8.dist-info/entry_points.txt,sha256=UXREYHuSl2XYd_tOtLIq0zg3d1kX3lixX5SpN8yGBw4,82
17
+ bitunix_automated_crypto_trading-3.1.8.dist-info/top_level.txt,sha256=uyFzHUCOsp8elnG2Ovor6xXcf7dxRxY-C-Txiwix64Q,33
18
+ bitunix_automated_crypto_trading-3.1.8.dist-info/RECORD,,
@@ -1,18 +0,0 @@
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=JIJumU3nYcO_NRS5xMqrPeisMIiy_TM0EOEA5nr44cQ,67993
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/SupportResistance.py,sha256=Dx4uBC4On-GO1t2EFk02jzSmZzaMD48mUJI9rG2rgMo,4946
8
- bitunix_automated_crypto_trading/ThreadManager.py,sha256=WmYRQu8aNrgp5HwSqpBqX1WESNSEpbD2CznPFpd9HuI,2330
9
- bitunix_automated_crypto_trading/TickerManager.py,sha256=n2GyvfH2YMuZ31Q_IcLd4U3ZOEIOLhLwMIR8iI5Gp5A,41460
10
- bitunix_automated_crypto_trading/__init__.py,sha256=1hzk6nX8NnUCr1tsq8oFq1qGCNhNwnwldWE75641Eew,78
11
- bitunix_automated_crypto_trading/bitunix.py,sha256=Zyrf8P-xi7DJogX_bcc6uDW66J7FAxdS-0jbuHRPFfM,25845
12
- bitunix_automated_crypto_trading/config.py,sha256=aBBHdkMnw4ODzcwQl1CCx_r1O08hShDRGlSA6JXt5lg,5024
13
- bitunix_automated_crypto_trading/logger.py,sha256=tAaTQcv5r--zupk_Fhfe1USfBAzSiXzVa4QRnaOFIFY,2933
14
- bitunix_automated_crypto_trading-3.1.6.dist-info/METADATA,sha256=CzoCXqOg2hhZOrZZ9UMEnC3ohtqNrWEi6xT17G7pjq0,996
15
- bitunix_automated_crypto_trading-3.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
- bitunix_automated_crypto_trading-3.1.6.dist-info/entry_points.txt,sha256=UXREYHuSl2XYd_tOtLIq0zg3d1kX3lixX5SpN8yGBw4,82
17
- bitunix_automated_crypto_trading-3.1.6.dist-info/top_level.txt,sha256=uyFzHUCOsp8elnG2Ovor6xXcf7dxRxY-C-Txiwix64Q,33
18
- bitunix_automated_crypto_trading-3.1.6.dist-info/RECORD,,