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.
- bitunix_automated_crypto_trading/BitunixApi.py +2 -0
- bitunix_automated_crypto_trading/BitunixSignal.py +3 -2
- bitunix_automated_crypto_trading/TickerManager.py +207 -133
- bitunix_automated_crypto_trading/bitunix.py +4 -70
- bitunix_automated_crypto_trading/config.py +9 -0
- {bitunix_automated_crypto_trading-3.1.2.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.2.dist-info → bitunix_automated_crypto_trading-3.1.3.dist-info}/WHEEL +1 -1
- bitunix_automated_crypto_trading-3.1.2.dist-info/RECORD +0 -17
- {bitunix_automated_crypto_trading-3.1.2.dist-info → bitunix_automated_crypto_trading-3.1.3.dist-info}/entry_points.txt +0 -0
- {bitunix_automated_crypto_trading-3.1.2.dist-info → bitunix_automated_crypto_trading-3.1.3.dist-info}/top_level.txt +0 -0
@@ -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
|
-
|
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(
|
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,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.
|
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.
|
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.
|
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
|
78
|
-
|
79
|
-
|
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['
|
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
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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.
|
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
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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.
|
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
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
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
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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.
|
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.
|
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
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
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
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
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
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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
|
-
|
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
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
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
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
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
|
|
@@ -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=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,,
|
File without changes
|
File without changes
|