bitunix-automated-crypto-trading 3.1.1__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.
- bitunix_automated_crypto_trading/BitunixApi.py +8 -8
- bitunix_automated_crypto_trading/BitunixSignal.py +4 -3
- bitunix_automated_crypto_trading/TickerManager.py +204 -137
- bitunix_automated_crypto_trading/bitunix.py +4 -70
- bitunix_automated_crypto_trading/config.py +9 -0
- {bitunix_automated_crypto_trading-3.1.1.dist-info → bitunix_automated_crypto_trading-3.1.3.dist-info}/METADATA +1 -1
- bitunix_automated_crypto_trading-3.1.3.dist-info/RECORD +17 -0
- {bitunix_automated_crypto_trading-3.1.1.dist-info → bitunix_automated_crypto_trading-3.1.3.dist-info}/WHEEL +1 -1
- bitunix_automated_crypto_trading-3.1.1.dist-info/RECORD +0 -17
- {bitunix_automated_crypto_trading-3.1.1.dist-info → bitunix_automated_crypto_trading-3.1.3.dist-info}/entry_points.txt +0 -0
- {bitunix_automated_crypto_trading-3.1.1.dist-info → bitunix_automated_crypto_trading-3.1.3.dist-info}/top_level.txt +0 -0
@@ -249,21 +249,21 @@ class BitunixApi:
|
|
249
249
|
function_name = stack[-2].name
|
250
250
|
logger.info(f"Function: {function_name}, {e}, {e.args}, {type(e).__name__}")
|
251
251
|
|
252
|
-
async def GetKlineHistory(self, ticker, interval, limit):
|
252
|
+
async def GetKlineHistory(self, ticker, interval, limit, starttime):
|
253
253
|
data = []
|
254
254
|
lm=limit
|
255
|
-
|
255
|
+
st=starttime
|
256
256
|
try:
|
257
257
|
while True:
|
258
|
-
url = f'{self.kline_Url}?symbol={ticker}&startTime={
|
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
|
262
|
-
|
263
|
-
|
261
|
+
if datajs['data'] == []:
|
262
|
+
break
|
263
|
+
data.extend(datajs['data'])
|
264
|
+
if len(datajs['data']) < lm:
|
265
|
+
st = int(datajs['data'][-1]['time']) + 1
|
264
266
|
lm=limit-len(data)
|
265
|
-
if len(data) >= limit:
|
266
|
-
break
|
267
267
|
else:
|
268
268
|
break
|
269
269
|
return data
|
@@ -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
|
-
|
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")
|
@@ -218,7 +219,7 @@ class BitunixSignal:
|
|
218
219
|
intervals = self.tickerObjects.get_intervalIds()
|
219
220
|
for ticker in self.tickerList:
|
220
221
|
for intervalId in intervals:
|
221
|
-
data = await self.bitunixApi.GetKlineHistory(ticker, intervalId, self.settings.BARS)
|
222
|
+
data = await self.bitunixApi.GetKlineHistory(ticker, intervalId, self.settings.BARS, int(time.time()))
|
222
223
|
if data is not None:
|
223
224
|
self.tickerObjects.load_kline_history(ticker, intervalId, self.settings.BARS, data)
|
224
225
|
if self.settings.VERBOSE_LOGGING:
|
@@ -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(
|
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
|
-
|
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,7 +99,6 @@ 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['ma_fast'] = df['ma_fast'].bfill()
|
57
102
|
df.fillna({'ma_fast':0}, inplace=True)
|
58
103
|
df['ma_fast_slope'] = df['ma_fast'].diff()
|
59
104
|
df['ma_fast_angle'] = np.degrees(np.arctan(df['ma_fast_slope']))
|
@@ -61,7 +106,6 @@ class Interval:
|
|
61
106
|
df.fillna({'ma_fast_angle':0}, inplace=True)
|
62
107
|
|
63
108
|
df['ma_medium'] = talib.EMA(df['close'], timeperiod=self.settings.MA_MEDIUM)
|
64
|
-
df['ma_medium'] = df['ma_medium'].bfill()
|
65
109
|
df.fillna({'ma_medium':0}, inplace=True)
|
66
110
|
df['ma_medium_slope'] = df['ma_medium'].diff()
|
67
111
|
df['ma_medium_angle'] = np.degrees(np.arctan(df['ma_medium_slope']))
|
@@ -69,7 +113,6 @@ class Interval:
|
|
69
113
|
df.fillna({'ma_medium_angle':0}, inplace=True)
|
70
114
|
|
71
115
|
df['ma_slow'] = talib.EMA(df['close'], timeperiod=self.settings.MA_SLOW)
|
72
|
-
df['ma_slow'] = df['ma_slow'].bfill()
|
73
116
|
df.fillna({'ma_slow':0}, inplace=True)
|
74
117
|
df['ma_slow_slope'] = df['ma_slow'].diff()
|
75
118
|
df['ma_slow_angle'] = np.degrees(np.arctan(df['ma_slow_slope']))
|
@@ -77,33 +120,35 @@ class Interval:
|
|
77
120
|
df.fillna({'ma_slow_angle':0}, inplace=True)
|
78
121
|
|
79
122
|
if self.settings.EMA_CROSSING:
|
80
|
-
if df
|
81
|
-
|
82
|
-
|
83
|
-
elif df['ma_medium'].iloc[-2] >= df['ma_slow'].iloc[-2] and df['ma_medium'].iloc[-1] < df['ma_slow'].iloc[-1]:
|
84
|
-
self.ema_open_signal = "SELL"
|
85
|
-
self.ema_close_signal = "SELL"
|
86
|
-
else:
|
87
|
-
self.ema_open_signal = "HOLD"
|
88
|
-
self.ema_close_signal = "HOLD"
|
89
|
-
|
90
|
-
if self.settings.EMA_CLOSE_ON_FAST_MEDIUM:
|
91
|
-
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"
|
92
126
|
self.ema_close_signal = "BUY"
|
93
|
-
elif df['
|
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"
|
94
129
|
self.ema_close_signal = "SELL"
|
95
130
|
else:
|
131
|
+
self.ema_open_signal = "HOLD"
|
96
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"
|
97
141
|
else:
|
98
|
-
if df
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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"
|
107
152
|
else:
|
108
153
|
# Drop EMA columns if not used
|
109
154
|
df.drop(['ma_fast', 'ma_medium', 'ma_slow', 'ma_slope', 'ma_angle'], axis=1, inplace=True, errors='ignore')
|
@@ -114,29 +159,29 @@ class Interval:
|
|
114
159
|
df['MACD_Signal'] = 0.0
|
115
160
|
df['MACD_Histogram'] = 0.0
|
116
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)
|
117
|
-
df.fillna({'MACD_Line':0}, inplace=True)
|
118
|
-
df.fillna({'MACD_Signal':0}, inplace=True)
|
119
|
-
df.fillna({'MACD_Histogram':0}, inplace=True)
|
120
|
-
|
162
|
+
df.fillna({'MACD_Line':0, 'MACD_Signal':0, 'MACD_Histogram':0}, inplace=True)
|
121
163
|
df['MACD_Line_slope'] = df['MACD_Line'].diff()
|
122
164
|
df['MACD_Line_angle'] = np.degrees(np.arctan(df['MACD_Line_slope']))
|
123
165
|
df.fillna({'MACD_Line_slope':0}, inplace=True)
|
124
|
-
df.fillna({'MACD_Line_angle':0}, inplace=True)
|
166
|
+
df.fillna({'MACD_Line_angle':0}, inplace=True)
|
167
|
+
|
125
168
|
|
126
169
|
if self.settings.MACD_CROSSING:
|
127
|
-
if df
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
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"
|
133
177
|
else:
|
134
|
-
if df
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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"
|
140
185
|
else:
|
141
186
|
# Drop MACD columns if not used
|
142
187
|
df.drop(['MACD_Line', 'MACD_Signal', 'MACD_Histogram', 'MACD_slope', 'MACD_angle'], axis=1, inplace=True, errors='ignore')
|
@@ -147,9 +192,7 @@ class Interval:
|
|
147
192
|
df['BBM'] = 0.0
|
148
193
|
df['BBU'] = 0.0
|
149
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, )
|
150
|
-
df.fillna({'BBL':0}, inplace=True)
|
151
|
-
df.fillna({'BBM':0}, inplace=True)
|
152
|
-
df.fillna({'BBU':0}, inplace=True)
|
195
|
+
df.fillna({'BBM':0, 'BBU':0, 'BBL':0}, inplace=True)
|
153
196
|
|
154
197
|
df['BBM_slope'] = df['BBM'].diff()
|
155
198
|
df['BBM_angle'] = np.degrees(np.arctan(df['BBM_slope']))
|
@@ -157,19 +200,21 @@ class Interval:
|
|
157
200
|
df.fillna({'BBM_angle':0}, inplace=True)
|
158
201
|
|
159
202
|
if self.settings.BBM_CROSSING:
|
160
|
-
if df
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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"
|
166
210
|
else:
|
167
|
-
if df
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
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"
|
173
218
|
else:
|
174
219
|
# Drop BBM columns if not used
|
175
220
|
df.drop(['BBL', 'BBM', 'BBU', 'BBM_slope', 'BBM_angle'], axis=1, inplace=True, errors='ignore')
|
@@ -192,54 +237,69 @@ class Interval:
|
|
192
237
|
|
193
238
|
|
194
239
|
if self.settings.RSI_CROSSING:
|
195
|
-
if df
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
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"
|
201
247
|
else:
|
202
|
-
if df
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
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"
|
208
255
|
else:
|
209
256
|
# Drop RSI columns if not used
|
210
257
|
df.drop(['rsi_fast', 'rsi_slow', 'rsi_slope', 'rsi_angle'], axis=1, inplace=True, errors='ignore')
|
211
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
|
+
|
212
270
|
# Calculate the ADX
|
213
271
|
if self.settings.ADX_STUDY:
|
214
|
-
df
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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"
|
220
279
|
else:
|
221
280
|
# Drop ADX columns if not used
|
222
281
|
df.drop(['ADX'], axis=1, inplace=True, errors='ignore')
|
223
282
|
|
224
283
|
# Calculate the close proximity
|
225
284
|
if self.settings.CANDLE_TREND_STUDY:
|
226
|
-
df
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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'
|
238
298
|
else:
|
239
299
|
# Drop candle trend columns if not used
|
240
300
|
df.drop(['candle_trend', 'range'], axis=1, inplace=True, errors='ignore')
|
241
301
|
|
242
|
-
|
302
|
+
|
243
303
|
#replace infinity
|
244
304
|
df.replace([np.inf, -np.inf], 0, inplace=True)
|
245
305
|
|
@@ -411,7 +471,8 @@ class Ticker:
|
|
411
471
|
self._intervals = intervals
|
412
472
|
|
413
473
|
def get_interval_ticks(self, intervalId):
|
414
|
-
|
474
|
+
interval = self._intervals.get(intervalId, None)
|
475
|
+
return interval
|
415
476
|
|
416
477
|
def set_interval_ticks(self, intervalId, new_value):
|
417
478
|
self._intervals[intervalId] = new_value
|
@@ -450,6 +511,7 @@ class Ticker:
|
|
450
511
|
ticks_interval=intervalObj.get_data()
|
451
512
|
if ticks_interval is None:
|
452
513
|
return
|
514
|
+
#print('create_bar_with_last_and_ts', self.symbol, intervalId, len(ticks_interval))
|
453
515
|
if len(ticks_interval)==0 or self._ts - ticks_interval[-1]['time'] >= intervalObj.delta:
|
454
516
|
ticks_interval.append(new_item)
|
455
517
|
current_bar = ticks_interval[-1]
|
@@ -464,6 +526,7 @@ class Ticker:
|
|
464
526
|
current_bar['barcolor'] = self.red if current_bar['close'] <= current_bar['open'] else self.green
|
465
527
|
#print(f'{self.symbol} {self._last}, {self._ts} {intervalId} {ticks_interval[-1]['time']} c' )
|
466
528
|
|
529
|
+
#print ('create_bar_with_last_and_ts', ticks_interval[-1])
|
467
530
|
intervalObj.set_data(ticks_interval)
|
468
531
|
|
469
532
|
except Exception as e:
|
@@ -567,24 +630,29 @@ class Tickers:
|
|
567
630
|
# since the calulation is done at a different thread and uses a different memory space,
|
568
631
|
# the caluated value has to be reassigned to the original ticker class instance from the caluated ticker instance
|
569
632
|
def form_candle(self, tuples_list):
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
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]
|
588
656
|
|
589
657
|
def getCurrentData(self, period):
|
590
658
|
current_data = []
|
@@ -603,33 +671,32 @@ class Tickers:
|
|
603
671
|
ticks = intervalObj.get_data()
|
604
672
|
if not ticks:
|
605
673
|
continue
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
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)
|
633
700
|
|
634
701
|
df = pd.DataFrame(current_data)
|
635
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
|
|
@@ -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,17 +0,0 @@
|
|
1
|
-
bitunix_automated_crypto_trading/AsyncThreadRunner.py,sha256=LJ6ny1KSCVoIbfeNypsY4aHYcbkGME9M3epQ9e8B1O8,3224
|
2
|
-
bitunix_automated_crypto_trading/BitunixApi.py,sha256=wJhknpmVFrckoL89h-nlWUAMsPxhIacY0nOGJT9M6Vw,11360
|
3
|
-
bitunix_automated_crypto_trading/BitunixSignal.py,sha256=LKxWy_-alKkawB_l9_AdzwtCt0rx6lTqfBDuiGBMoe4,64669
|
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=eeOK5paiae10XHjKMbucJnVAZkAsEC86N37bRPuCcFc,33427
|
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.1.dist-info/METADATA,sha256=5cwQuEB4OsaVHSAxpiYo0gIDSK3Rs39TgID_E7dCihU,996
|
14
|
-
bitunix_automated_crypto_trading-3.1.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
15
|
-
bitunix_automated_crypto_trading-3.1.1.dist-info/entry_points.txt,sha256=UXREYHuSl2XYd_tOtLIq0zg3d1kX3lixX5SpN8yGBw4,82
|
16
|
-
bitunix_automated_crypto_trading-3.1.1.dist-info/top_level.txt,sha256=uyFzHUCOsp8elnG2Ovor6xXcf7dxRxY-C-Txiwix64Q,33
|
17
|
-
bitunix_automated_crypto_trading-3.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|