bitunix-automated-crypto-trading 3.3.5__tar.gz → 3.3.7__tar.gz
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-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/PKG-INFO +1 -1
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/README.md +5 -2
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/BitunixSignal.py +65 -38
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/TickerManager.py +2 -2
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/config.py +3 -1
- bitunix_automated_crypto_trading-3.3.7/bitunix_automated_crypto_trading/version.py +1 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading.egg-info/PKG-INFO +1 -1
- bitunix_automated_crypto_trading-3.3.5/bitunix_automated_crypto_trading/version.py +0 -1
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/AsyncThreadRunner.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/BitunixApi.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/BitunixWebSocket.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/DataFrameHtmlRenderer.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/NotificationManager.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/SupportResistance.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/ThreadManager.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/__init__.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/bitunix.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading/logger.py +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading.egg-info/SOURCES.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading.egg-info/dependency_links.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading.egg-info/entry_points.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading.egg-info/requires.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/bitunix_automated_crypto_trading.egg-info/top_level.txt +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/setup.cfg +0 -0
- {bitunix_automated_crypto_trading-3.3.5 → bitunix_automated_crypto_trading-3.3.7}/setup.py +0 -0
@@ -63,8 +63,10 @@ The platform can be configured through the `config.py` file or `config.txt`. Key
|
|
63
63
|
- `LOSS_PERCENTAGE`: Maximum loss ROI percentage
|
64
64
|
- `BOT_CONTROLS_TP_SL`: True or False
|
65
65
|
if false then take profit and stop loss will be placed by the bot when TP or SL is reached, if true then take profit and stop loss will be placed when the trade is opened
|
66
|
-
- `
|
67
|
-
if set to True then bot will
|
66
|
+
- `BOT_TRAIL_TP`
|
67
|
+
if set to True then bot will trail the TP in the direction of profit
|
68
|
+
- `BOT_TRAIL_SL`
|
69
|
+
if set to True then bot will trail the SL in the direction of profit
|
68
70
|
- `PROFIT_LOSS_PRICE_TYPE`: "MARK_PRICE" or "LAST_PRICE"
|
69
71
|
- `PROFIT_LOSS_ORDER_TYPE`: "MARKET" or "LIMIT"
|
70
72
|
- `OPTION_MOVING_AVERAGE`: Moving average period (1h, 1d, 15m, 5m, 1m)
|
@@ -83,6 +85,7 @@ The platform can be configured through the `config.py` file or `config.txt`. Key
|
|
83
85
|
- `MACD_SHORT`: MACD short period
|
84
86
|
- `MACD_LONG`: MACD long period
|
85
87
|
- `ADX_PERIOD`: ADX period
|
88
|
+
- `MINIMUM_CONSECUTIVE_CANDLES`: Minimum number of consecutive candles to consider for a signal.
|
86
89
|
|
87
90
|
- `Study Parameters`:
|
88
91
|
- `EMA_STUDY`: Enable EMA study
|
@@ -643,27 +643,21 @@ class BitunixSignal:
|
|
643
643
|
del inuse1, inuse2, inuseTickers
|
644
644
|
gc.collect()
|
645
645
|
|
646
|
-
|
647
|
-
"""Calculates the duration in minutes from trade time to current time."""
|
648
|
-
current_time_unix = int(time.time()) # Get current Unix timestamp
|
649
|
-
print(f"Current time (Unix): {current_time_unix}, Trade time (Unix): {trade_time_unix}")
|
650
|
-
duration_seconds = current_time_unix - trade_time_unix
|
651
|
-
duration_minutes = duration_seconds / 60 # Convert seconds to minutes
|
652
|
-
return round(duration_minutes)
|
653
|
-
|
646
|
+
|
654
647
|
async def get_duration(self,datetime_str):
|
655
648
|
"""Calculates the duration in minutes from a given datetime string to the current time."""
|
656
649
|
# Convert input datetime string to a datetime object
|
657
650
|
trade_time = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S")
|
658
|
-
|
659
|
-
# Convert datetime object to Unix timestamp
|
651
|
+
# Convert datetime object to Unix timestamp)
|
660
652
|
trade_time_unix = int(trade_time.timestamp())
|
661
|
-
|
653
|
+
#print(f"trade_time_unix: {trade_time_unix}, trade_time: {trade_time}")
|
662
654
|
# Get current Unix timestamp
|
663
655
|
current_time_unix = int(time.time())
|
664
|
-
|
656
|
+
#print(f"current_time_unix: {current_time_unix}, time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
665
657
|
# Calculate duration in minutes
|
666
658
|
duration_minutes = (current_time_unix - trade_time_unix) / 60
|
659
|
+
#print(f"diff: {current_time_unix - trade_time_unix}")
|
660
|
+
#print(f"duration_minutes: {duration_minutes}")
|
667
661
|
|
668
662
|
return round(duration_minutes)
|
669
663
|
|
@@ -735,6 +729,7 @@ class BitunixSignal:
|
|
735
729
|
self.logger.info(f"row.symbol: {row.symbol} , duration_minutes: {duration_minutes}, last trade time: {mtime if duration_minutes is not None else 'N/A'}")
|
736
730
|
if duration_minutes is None or duration_minutes > self.settings.DELAY_IN_MINUTES_FOR_SAME_TICKER_TRADES:
|
737
731
|
side = "BUY" if row[f'{period}_barcolor'] == self.green and row[f'{period}_trend'] == "BUY" else "SELL" if row[f'{period}_barcolor'] == self.red and row[f'{period}_trend'] == "SELL" else ""
|
732
|
+
#self.logger.info(f"row.symbol: {row.symbol} , ok to {side}, {row[f'{period}_barcolor']} , {row[f'{period}_trend']} ")
|
738
733
|
if side != "":
|
739
734
|
select = True
|
740
735
|
self.pendingPositions = await self.bitunixApi.GetPendingPositionData({'symbol': row.symbol})
|
@@ -798,6 +793,7 @@ class BitunixSignal:
|
|
798
793
|
count=count+1
|
799
794
|
else:
|
800
795
|
self.logger.info(f"Skipping {row.symbol} as it has been opened for less than {self.settings.DELAY_IN_MINUTES_FOR_SAME_TICKER_TRADES} minutes")
|
796
|
+
|
801
797
|
if count >= int(self.settings.MAX_AUTO_TRADES):
|
802
798
|
break
|
803
799
|
await asyncio.sleep(0)
|
@@ -812,7 +808,7 @@ class BitunixSignal:
|
|
812
808
|
current_time = time.time() * 1000
|
813
809
|
df=self.orderdf.copy(deep=False)
|
814
810
|
for index, row in df.iterrows():
|
815
|
-
if current_time - int(row.ctime) >
|
811
|
+
if current_time - int(row.ctime) > 60000:
|
816
812
|
self.notifications.add_notification(
|
817
813
|
f'{colors.LBLUE} Canceling order {row.orderId}, {row.symbol} {row.qty} created at {row.rtime} '
|
818
814
|
)
|
@@ -829,8 +825,8 @@ class BitunixSignal:
|
|
829
825
|
|
830
826
|
# Calculate the duration in minutes since the position was opened
|
831
827
|
ctime = row['ctime']
|
832
|
-
duration_minutes = await self.get_duration(ctime)
|
833
|
-
no_of_candles_since_current_open = await self.calculate_candles(period, duration_minutes)
|
828
|
+
#duration_minutes = await self.get_duration(ctime)
|
829
|
+
#no_of_candles_since_current_open = await self.calculate_candles(period, duration_minutes)
|
834
830
|
|
835
831
|
requiredCols=[f'{period}_open', f'{period}_close', f'{period}_high', f'{period}_low', f'{period}_ema_open', f"{period}_ema_close", f'{period}_macd', f'{period}_bbm', f'{period}_rsi', f'{period}_trendline', f'{period}_candle_trend', f'{period}_trend', f'{period}_cb', f'{period}_barcolor']
|
836
832
|
required_cols = set(requiredCols)
|
@@ -846,7 +842,7 @@ class BitunixSignal:
|
|
846
842
|
|
847
843
|
if select and int(self.settings.MAX_AUTO_TRADES)!=0:
|
848
844
|
|
849
|
-
if self.settings.
|
845
|
+
if self.settings.PROFIT_PERCENTAGE > 0 and self.settings.LOSS_PERCENTAGE > 0:
|
850
846
|
last, bid, ask, mtv = await self.GetTickerBidLastAsk(row.symbol)
|
851
847
|
price = (bid if side == "BUY" else ask if side == "SELL" else last) if bid<=last<=ask else last
|
852
848
|
decimal_places = abs(Decimal(str(price)).as_tuple().exponent)
|
@@ -861,13 +857,17 @@ class BitunixSignal:
|
|
861
857
|
old_tpPrice = None
|
862
858
|
tpStopType = self.settings.SL_STOP_TYPE
|
863
859
|
tpOrderType = self.settings.SL_ORDER_TYPE
|
860
|
+
tpOrderPrice = None
|
864
861
|
|
865
862
|
slPrice = None
|
866
863
|
slorderId = None
|
867
864
|
old_slPrice = None
|
868
865
|
slStopType = self.settings.SL_STOP_TYPE
|
869
866
|
slOrderType = self.settings.SL_ORDER_TYPE
|
867
|
+
slOrderPrice = None
|
870
868
|
|
869
|
+
roi = round((row['unrealizedPNL'] / (row['qty'] * row['avgOpenPrice'])) * 100 * self.settings.LEVERAGE,2)
|
870
|
+
|
871
871
|
datajs = await self.bitunixApi.GetPendingTpSlOrderData({'symbol': symbol})
|
872
872
|
if datajs:
|
873
873
|
for order in datajs:
|
@@ -885,33 +885,60 @@ class BitunixSignal:
|
|
885
885
|
old_slPrice = slPrice
|
886
886
|
|
887
887
|
# move TP and SL in the direction of profit
|
888
|
-
|
889
|
-
|
888
|
+
tp_midpoint = None
|
889
|
+
sl_midpoint = None
|
890
|
+
if self.settings.BOT_TRAIL_TP:
|
891
|
+
if old_tpPrice is not None:
|
892
|
+
tp_midpoint = old_tpPrice / (1 + self.settings.PROFIT_PERCENTAGE/100/self.settings.LEVERAGE) if side == "BUY" else old_tpPrice / (1 - self.settings.PROFIT_PERCENTAGE/100/self.settings.LEVERAGE) if tpPrice is not None else None
|
893
|
+
if tp_midpoint is not None and (price > tp_midpoint and side == "BUY" or price < tp_midpoint and side == "SELL"):
|
890
894
|
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
+
tpPrice = price * (1 + float(self.settings.PROFIT_PERCENTAGE) / 100 / self.settings.LEVERAGE) if side == "BUY" else price * (1 - float(self.settings.PROFIT_PERCENTAGE) / 100 / self.settings.LEVERAGE)
|
896
|
+
tpPrice = Decimal(await self.str_precision(tpPrice))
|
897
|
+
tpPrice =float(str(tpPrice.quantize(Decimal(f'1e-{decimal_places}'))))
|
898
|
+
tpOrderPrice = await self.decrement_by_last_decimal(str(tpPrice))
|
895
899
|
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
+
|
901
|
+
if self.settings.BOT_TRAIL_SL:
|
902
|
+
if old_slPrice is not None:
|
903
|
+
sl_midpoint = old_slPrice / (1 - self.settings.LOSS_PERCENTAGE/100/self.settings.LEVERAGE) if side == "BUY" else old_slPrice / (1 + self.settings.LOSS_PERCENTAGE/100/self.settings.LEVERAGE) if tpPrice is not None else None
|
904
|
+
if roi > self.settings.PROFIT_PERCENTAGE:
|
905
|
+
sl_midpoint = tp_midpoint
|
906
|
+
|
907
|
+
if sl_midpoint is not None and (price > sl_midpoint and side == "BUY" or price < sl_midpoint and side == "SELL"):
|
908
|
+
if roi > self.settings.PROFIT_PERCENTAGE and self.settings.PROFIT_PERCENTAGE < self.settings.LOSS_PERCENTAGE:
|
909
|
+
slPrice = price * (1 - float(self.settings.PROFIT_PERCENTAGE) / 100 / self.settings.LEVERAGE) if side == "BUY" else price * (1 + float(self.settings.PROFIT_PERCENTAGE) / 100 / self.settings.LEVERAGE)
|
910
|
+
else:
|
911
|
+
slPrice = price * (1 - float(self.settings.LOSS_PERCENTAGE) / 100 / self.settings.LEVERAGE) if side == "BUY" else price * (1 + float(self.settings.LOSS_PERCENTAGE) / 100 / self.settings.LEVERAGE)
|
912
|
+
slPrice = Decimal(await self.str_precision(slPrice))
|
913
|
+
slPrice = float(str(slPrice.quantize(Decimal(f'1e-{decimal_places}'))))
|
914
|
+
slOrderPrice = await self.increment_by_last_decimal(await self.str_precision(slPrice))
|
900
915
|
|
916
|
+
if (self.settings.BOT_TRAIL_TP and tpOrderPrice is not None) or (self.settings.BOT_TRAIL_SL and slOrderPrice is not None):
|
901
917
|
self.notifications.add_notification(
|
902
|
-
f'{colors.CYAN} {row.symbol} TP
|
918
|
+
f'{colors.CYAN} {row.symbol} avgOpenPrice: {avgOpenPrice}, current price: {price}, ROI: {roi}%, TP: {old_tpPrice}, TP midpoint: {tp_midpoint}, new TP: {tpPrice}, SL: {old_slPrice}, SL midpoint: {sl_midpoint}, new SL: {slPrice}'
|
903
919
|
)
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
920
|
+
|
921
|
+
|
922
|
+
if self.settings.BOT_TRAIL_TP and tpPrice is not None and tpOrderPrice is not None:
|
923
|
+
datajs2 = await self.bitunixApi.ModifyTpSlOrder({'orderId':tporderId,'tpPrice':str(tpPrice), 'tpOrderPrice':str(tpOrderPrice), 'tpQty':str(qty),'tpStopType':tpStopType,'tpOrderType':tpOrderType})
|
924
|
+
if datajs2 is not None:
|
925
|
+
self.notifications.add_notification(
|
926
|
+
f'{colors.CYAN} Take Profit order for {row.symbol} moved from {old_tpPrice} to {tpPrice}'
|
927
|
+
)
|
928
|
+
|
929
|
+
if self.settings.BOT_TRAIL_SL and slPrice is not None and slOrderPrice is not None:
|
930
|
+
datajs3 = await self.bitunixApi.ModifyTpSlOrder({'orderId':slorderId,'slPrice':str(slPrice),'slQty':str(qty),'slStopType':slStopType,'slOrderType':slOrderType})
|
931
|
+
if datajs3 is not None:
|
932
|
+
if roi > self.settings.PROFIT_PERCENTAGE and self.settings.PROFIT_PERCENTAGE < self.settings.LOSS_PERCENTAGE:
|
933
|
+
self.notifications.add_notification(
|
934
|
+
f'{colors.CYAN} Stop Loss order for {row.symbol} moved from {old_slPrice} to breakeven {slPrice}'
|
935
|
+
)
|
936
|
+
else:
|
937
|
+
self.notifications.add_notification(
|
938
|
+
f'{colors.CYAN} Stop Loss order for {row.symbol} moved from {old_slPrice} to {slPrice}'
|
939
|
+
)
|
940
|
+
|
941
|
+
|
915
942
|
|
916
943
|
if self.settings.BOT_CONTROLS_TP_SL:
|
917
944
|
# check take profit amount or accept loss amount
|
@@ -750,13 +750,13 @@ class Tickers:
|
|
750
750
|
trending_conditions = [
|
751
751
|
(
|
752
752
|
(df[f'{period}_trend']=='BUY') &
|
753
|
-
(df[f'{period}_cb']
|
753
|
+
(df[f'{period}_cb']>= self.settings.MINIMUM_CONSECUTIVE_CANDLES)
|
754
754
|
#&
|
755
755
|
#(df[f'{period}_barcolor']==self.green)
|
756
756
|
),
|
757
757
|
(
|
758
758
|
(df[f'{period}_trend']=='SELL') &
|
759
|
-
(df[f'{period}_cb']
|
759
|
+
(df[f'{period}_cb']>= self.settings.MINIMUM_CONSECUTIVE_CANDLES)
|
760
760
|
#&
|
761
761
|
#(df[f'{period}_barcolor']==self.red)
|
762
762
|
)
|
@@ -22,7 +22,8 @@ class Settings(BaseSettings):
|
|
22
22
|
PROFIT_AMOUNT: float = Field(default=0, ge=0.0)
|
23
23
|
LOSS_AMOUNT: float = Field(default=5.0, ge=0.0)
|
24
24
|
BOT_CONTROLS_TP_SL: bool = Field(default=False)
|
25
|
-
|
25
|
+
BOT_TRAIL_TP: bool = Field(default=False)
|
26
|
+
BOT_TRAIL_SL: bool = Field(default=False)
|
26
27
|
TP_STOP_TYPE: str = Field(default="MARK_PRICE")
|
27
28
|
TP_ORDER_TYPE: str = Field(default="LIMIT")
|
28
29
|
SL_STOP_TYPE: str = Field(default="MARK_PRICE")
|
@@ -43,6 +44,7 @@ class Settings(BaseSettings):
|
|
43
44
|
MACD_SHORT: int = Field(default=12, ge=1)
|
44
45
|
MACD_LONG: int = Field(default=26, ge=1)
|
45
46
|
ADX_PERIOD: int = Field(default=14, ge=1)
|
47
|
+
MINIMUM_CONSECUTIVE_CANDLES: int = Field(default=2, ge=1)
|
46
48
|
|
47
49
|
# Technical Indicators
|
48
50
|
OPEN_ON_ANY_SIGNAL: bool = Field(default=True)
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "3.3.7"
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "3.3.5"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|