Closed wikitab closed 5 months ago
idem chez moi
en fait comme très souvent, les libs c'est bullshit, ici ccxt, c'est un vrai merdier, pourquoi s'en servir alors qu'on peut tout simplement utiliser directement les endpoints de bitget. Je vais tout recoder moi même.
Hello je n'ai pas de problème de mon côté donc je pense que c'est un soucis de version de ccxt. J'ai ajusté un peu le répertoire pour utiliser un environnement virtuel et éviter les soucis de ce type. Pour ce faire ce que je vous conseille c'est reprendre de zéro. Pour ça supprimer le dossier :
sudo rm -r Live-Tools-V2/
Puis retélécharger :
git clone https://github.com/CryptoRobotFr/Live-Tools-V2.git
bash Live-Tools-V2/install.sh
Pensez à bien remettre votre clé api et normalement cela devrait être bon. Pour tester :
bash Live-Tools-V2/1hcron.sh
Hello,
Merci pour ta réponse.
Je suis reparti de zéro avec les fichiers modifiés sur GIT (avec les packages avec les bonnes version), mais j'ai encore la même erreur après avoir fait un short manuel de 0.01 ETH.
Je ne sais pas si ça a un impact, mais lors de l'install, j'ai un message sur la console SSH : voir la capture d'écran
--- Execution started at 2024-01-29 19:32:54 ---
Pair REN/USDT not found, removing from params...
Setting isolated x3 on 21 pairs...
Getting data and indicators on 21 pairs...
Balance: XXXXXXXXXX USDT
Getting open trigger orders...
Canceling trigger orders...
Getting open orders...
Canceling limit orders...
Getting live positions...
Current position on ETH/USDT short - 0.01 ~ 23.0 $
Placing 2 close SL / limit order...
Traceback (most recent call last):
File "/home/ubuntu/Live-Tools-V2/strategies/envelopes/multi_bitget.py", line 443, in
A+ ;-)
Hello,
Exactement le même pb pour moi, j'ai tout essayé ccxt .20, .21, .22 et .23 et je viens une nouvelle fois de réinstaller le projet.
Les ordres ne se mettents plus dès que l'on a des positions ouvertes.
Voici la trace :
--- Execution started at 2024-01-31 13:45:48 ---
Setting crossed x4 on 22 pairs...
Getting data and indicators on 22 pairs...
Balance: 406.32 USDT
Getting open trigger orders...
Canceling trigger orders...
Getting open orders...
Canceling limit orders...
Getting live positions...
Current position on ROSE/USDT long - 207.0 ~ 21.03 $
Placing 2 close SL / limit order...
Traceback (most recent call last):
File "/home/ubuntu/Live-Tools-V2/strategies/envelopes/multi_bitget.py", line 443, in
Merci,
Re,
J'ai décommenté les lignes margin_mode dans les fonctions place_order et place_trigger_order et tout fonctionne maintenant :
async def place_order(
self,
pair,
side,
price,
size,
type="limit",
reduce=False,
margin_mode="crossed",
error=True,
) -> Order:
try:
pair = self.ext_pair_to_pair(pair)
trade_side = "Open" if reduce is False else "Close"
resp = await self._session.create_order(
symbol=pair,
type=type,
side=side,
amount=size,
price=price,
params={
"reduceOnly": reduce,
"tradeSide": trade_side,
# "marginMode": margin_mode,
},
)
order_id = resp["id"]
pair = self.pair_to_ext_pair(resp["symbol"])
order = await self.get_order_by_id(order_id, pair)
return order
except Exception as e:
if error:
raise e
else:
print(e)
return None
async def place_trigger_order(
self,
pair,
side,
price,
trigger_price,
size,
type="limit",
reduce=False,
margin_mode="crossed",
error=True,
) -> Info:
try:
pair = self.ext_pair_to_pair(pair)
trade_side = "Open" if reduce is False else "Close"
trigger_order = await self._session.create_trigger_order(
symbol=pair,
type=type,
side=side,
amount=size,
price=price,
triggerPrice=trigger_price,
params={
"reduceOnly": reduce,
"tradeSide": trade_side,
# "marginMode": margin_mode,
},
)
resp = Info(success=True, message="Trigger Order set up")
return resp
except Exception as e:
if error:
raise e
else:
print(e)
return None
Voici la dernière trace :
--- Execution started at 2024-01-31 13:56:36 --- Setting crossed x4 on 22 pairs... Getting data and indicators on 22 pairs... Balance: 406.25 USDT Getting open trigger orders... Canceling trigger orders... Getting open orders... Canceling limit orders... Getting live positions... Current position on ROSE/USDT long - 207.0 ~ 20.99 $ Placing 2 close SL / limit order... Placing 202 open limit order... --- Execution finished at 2024-01-31 13:58:02 ---
@CryptoRobotFr peux-tu nous confirmer si c'était bien ça le pb ?
Merci beaucoup,
Alexandre.
Hello,
Pour info j'ai les deux scripts sur deux comptes (un en crossed et l'autre en isolated) --> l'erreur margin mode lorsqu'une position est ouverte ne se produit que sur les positions crossed. Il n'y a aucune erreur avec mon autre script qui est sur des positions isolated.
Re,
J'ai décommenté les lignes margin_mode dans les fonctions place_order et place_trigger_order et tout fonctionne maintenant :
async def place_order( self, pair, side, price, size, type="limit", reduce=False, margin_mode="crossed", error=True, ) -> Order: try: pair = self.ext_pair_to_pair(pair) trade_side = "Open" if reduce is False else "Close" resp = await self._session.create_order( symbol=pair, type=type, side=side, amount=size, price=price, params={ "reduceOnly": reduce, "tradeSide": trade_side, # "marginMode": margin_mode, }, ) order_id = resp["id"] pair = self.pair_to_ext_pair(resp["symbol"]) order = await self.get_order_by_id(order_id, pair) return order except Exception as e: if error: raise e else: print(e) return None async def place_trigger_order( self, pair, side, price, trigger_price, size, type="limit", reduce=False, margin_mode="crossed", error=True, ) -> Info: try: pair = self.ext_pair_to_pair(pair) trade_side = "Open" if reduce is False else "Close" trigger_order = await self._session.create_trigger_order( symbol=pair, type=type, side=side, amount=size, price=price, triggerPrice=trigger_price, params={ "reduceOnly": reduce, "tradeSide": trade_side, # "marginMode": margin_mode, }, ) resp = Info(success=True, message="Trigger Order set up") return resp except Exception as e: if error: raise e else: print(e) return None
Voici la dernière trace :
--- Execution started at 2024-01-31 13:56:36 --- Setting crossed x4 on 22 pairs... Getting data and indicators on 22 pairs... Balance: 406.25 USDT Getting open trigger orders... Canceling trigger orders... Getting open orders... Canceling limit orders... Getting live positions... Current position on ROSE/USDT long - 207.0 ~ 20.99 $ Placing 2 close SL / limit order... Placing 202 open limit order... --- Execution finished at 2024-01-31 13:58:02 ---
@CryptoRobotFr peux-tu nous confirmer si c'était bien ça le pb ?
Merci beaucoup,
Alexandre.
Je confirme. C'est dans le fichier "Live-Tools-V2/utilities/bitget_perp.py" qu'il faut apporter la modification.
hello, moi j'ai toujours l'erreur, alors que je suis bien en isolated et j'ai également modifié le script vitget_perp.py Je met mon script en dessous.
Merci les gars :) :
`from typing import List import ccxt.async_support as ccxt import asyncio import pandas as pd import time import itertools from pydantic import BaseModel
class UsdtBalance(BaseModel): total: float free: float used: float
class Info(BaseModel): success: bool message: str
class Order(BaseModel): id: str pair: str type: str side: str price: float size: float reduce: bool filled: float remaining: float timestamp: int
class TriggerOrder(BaseModel): id: str pair: str type: str side: str price: float trigger_price: float size: float reduce: bool timestamp: int
class Position(BaseModel): pair: str side: str size: float usd_size: float entry_price: float current_price: float unrealizedPnl: float liquidation_price: float margin_mode: str leverage: float hedge_mode: bool open_timestamp: int take_profit_price: float stop_loss_price: float
class PerpBitget: def init(self, public_api=None, secret_api=None, password=None): bitget_auth_object = { "apiKey": public_api, "secret": secret_api, "password": password, "enableRateLimit": True, "rateLimit": 100, "options": { "defaultType": "future", }, } if bitget_auth_object["secret"] == None: self._auth = False self._session = ccxt.bitget() else: self._auth = True self._session = ccxt.bitget(bitget_auth_object)
async def load_markets(self):
self.market = await self._session.load_markets()
async def close(self):
await self._session.close()
def ext_pair_to_pair(self, ext_pair) -> str:
return f"{ext_pair}:USDT"
def pair_to_ext_pair(self, pair) -> str:
return pair.replace(":USDT", "")
def get_pair_info(self, ext_pair) -> str:
pair = self.ext_pair_to_pair(ext_pair)
if pair in self.market:
return self.market[pair]
else:
return None
def amount_to_precision(self, pair: str, amount: float) -> float:
pair = self.ext_pair_to_pair(pair)
return self._session.amount_to_precision(pair, amount)
def price_to_precision(self, pair: str, price: float) -> float:
pair = self.ext_pair_to_pair(pair)
return self._session.price_to_precision(pair, price)
async def get_last_ohlcv(self, pair, timeframe, limit=1000) -> pd.DataFrame:
pair = self.ext_pair_to_pair(pair)
bitget_limit = 200
ts_dict = {
"1m": 1 * 60 * 1000,
"5m": 5 * 60 * 1000,
"15m": 15 * 60 * 1000,
"1h": 60 * 60 * 1000,
"2h": 2 * 60 * 60 * 1000,
"4h": 4 * 60 * 60 * 1000,
"1d": 24 * 60 * 60 * 1000,
}
end_ts = int(time.time() * 1000)
start_ts = end_ts - ((limit) * ts_dict[timeframe])
current_ts = start_ts
tasks = []
while current_ts < end_ts:
req_end_ts = min(current_ts + (bitget_limit * ts_dict[timeframe]), end_ts)
tasks.append(
self._session.fetch_ohlcv(
pair,
timeframe,
params={
"limit": bitget_limit,
"startTime": str(current_ts),
"endTime": str(req_end_ts),
},
)
)
current_ts += (bitget_limit * ts_dict[timeframe]) + 1
ohlcv_unpack = await asyncio.gather(*tasks)
ohlcv_list = list(itertools.chain.from_iterable(ohlcv_unpack))
df = pd.DataFrame(
ohlcv_list, columns=["date", "open", "high", "low", "close", "volume"]
)
df = df.set_index(df["date"])
df.index = pd.to_datetime(df.index, unit="ms")
df = df.sort_index()
del df["date"]
return df
async def get_balance(self) -> UsdtBalance:
resp = await self._session.fetch_balance()
return UsdtBalance(
total=resp["USDT"]["total"],
free=resp["USDT"]["free"],
used=resp["USDT"]["used"],
)
async def set_margin_mode_and_leverage(self, pair, margin_mode, leverage):
if margin_mode not in ["crossed", "isolated"]:
raise Exception("Margin mode must be either 'crossed' or 'isolated'")
pair = self.ext_pair_to_pair(pair)
try:
await self._session.set_margin_mode(
margin_mode,
pair,
params={"productType": "USDT-FUTURES", "marginCoin": "USDT"},
)
except Exception as e:
pass
try:
if margin_mode == "isolated":
tasks = []
tasks.append(
self._session.set_leverage(
leverage,
pair,
params={
"productType": "USDT-FUTURES",
"marginCoin": "USDT",
"holdSide": "long",
},
)
)
tasks.append(
self._session.set_leverage(
leverage,
pair,
params={
"productType": "USDT-FUTURES",
"marginCoin": "USDT",
"holdSide": "short",
},
)
)
await asyncio.gather(*tasks)
else:
await self._session.set_leverage(
leverage,
pair,
params={"productType": "USDT-FUTURES", "marginCoin": "USDT"},
)
except Exception as e:
pass
return Info(
success=True,
message=f"Margin mode and leverage set to {margin_mode} and {leverage}x",
)
async def get_open_positions(self, pairs) -> List[Position]:
pairs = [self.ext_pair_to_pair(pair) for pair in pairs]
resp = await self._session.fetch_positions(
symbols=pairs, params={"productType": "USDT-FUTURES", "marginCoin": "USDT"}
)
return_positions = []
for position in resp:
liquidation_price = 0
take_profit_price = 0
stop_loss_price = 0
if position["liquidationPrice"]:
liquidation_price = position["liquidationPrice"]
if position["takeProfitPrice"]:
take_profit_price = position["takeProfitPrice"]
if position["stopLossPrice"]:
stop_loss_price = position["stopLossPrice"]
return_positions.append(
Position(
pair=self.pair_to_ext_pair(position["symbol"]),
side=position["side"],
size=position["contracts"] * position["contractSize"],
usd_size=round(
(position["contracts"] * position["contractSize"])
* position["markPrice"],
2,
),
entry_price=position["entryPrice"],
current_price=position["markPrice"],
unrealizedPnl=position["unrealizedPnl"],
liquidation_price=liquidation_price,
leverage=position["leverage"],
margin_mode=position["marginMode"],
hedge_mode=position["hedged"],
open_timestamp=position["timestamp"],
take_profit_price=take_profit_price,
stop_loss_price=stop_loss_price,
)
)
return return_positions
async def place_order(
self,
pair,
side,
price,
size,
type="limit",
reduce=False,
margin_mode="crossed",
error=True,
) -> Order:
try:
pair = self.ext_pair_to_pair(pair)
trade_side = "Open" if reduce is False else "Close"
resp = await self._session.create_order(
symbol=pair,
type=type,
side=side,
amount=size,
price=price,
params={
"reduceOnly": reduce,
"tradeSide": trade_side,
# "marginMode": margin_mode,
},
)
order_id = resp["id"]
pair = self.pair_to_ext_pair(resp["symbol"])
order = await self.get_order_by_id(order_id, pair)
return order
except Exception as e:
if error:
raise e
else:
print(e)
return None
async def place_trigger_order(
self,
pair,
side,
price,
trigger_price,
size,
type="limit",
reduce=False,
margin_mode="crossed",
error=True,
) -> Info:
try:
pair = self.ext_pair_to_pair(pair)
trade_side = "Open" if reduce is False else "Close"
trigger_order = await self._session.create_trigger_order(
symbol=pair,
type=type,
side=side,
amount=size,
price=price,
triggerPrice=trigger_price,
params={
"reduceOnly": reduce,
"tradeSide": trade_side,
# "marginMode": margin_mode,
},
)
resp = Info(success=True, message="Trigger Order set up")
return resp
except Exception as e:
if error:
raise e
else:
print(e)
return None
async def get_open_orders(self, pair) -> List[Order]:
pair = self.ext_pair_to_pair(pair)
resp = await self._session.fetch_open_orders(pair)
return_orders = []
for order in resp:
return_orders.append(
Order(
id=order["id"],
pair=self.pair_to_ext_pair(order["symbol"]),
type=order["type"],
side=order["side"],
price=order["price"],
size=order["amount"],
reduce=order["reduceOnly"],
filled=order["filled"],
remaining=order["remaining"],
timestamp=order["timestamp"],
)
)
return return_orders
async def get_open_trigger_orders(self, pair) -> List[TriggerOrder]:
pair = self.ext_pair_to_pair(pair)
resp = await self._session.fetch_open_orders(pair, params={"stop": True})
# print(resp)
return_orders = []
for order in resp:
reduce = True if order["info"]["tradeSide"] == "close" else False
price = order["price"] if order["price"] else 0.0
return_orders.append(
TriggerOrder(
id=order["id"],
pair=self.pair_to_ext_pair(order["symbol"]),
type=order["type"],
side=order["side"],
price=price,
trigger_price=order["triggerPrice"],
size=order["amount"],
reduce=reduce,
timestamp=order["timestamp"],
)
)
return return_orders
async def get_order_by_id(self, order_id, pair) -> Order:
pair = self.ext_pair_to_pair(pair)
resp = await self._session.fetch_order(order_id, pair)
return Order(
id=resp["id"],
pair=self.pair_to_ext_pair(resp["symbol"]),
type=resp["type"],
side=resp["side"],
price=resp["price"],
size=resp["amount"],
reduce=resp["reduceOnly"],
filled=resp["filled"],
remaining=resp["remaining"],
timestamp=resp["timestamp"],
)
async def cancel_orders(self, pair, ids=[]):
try:
pair = self.ext_pair_to_pair(pair)
resp = await self._session.cancel_orders(
ids=ids,
symbol=pair,
)
return Info(success=True, message=f"{len(resp)} Orders cancelled")
except Exception as e:
return Info(success=False, message="Error or no orders to cancel")
async def cancel_trigger_orders(self, pair, ids=[]):
try:
pair = self.ext_pair_to_pair(pair)
resp = await self._session.cancel_orders(
ids=ids, symbol=pair, params={"stop": True}
)
return Info(success=True, message=f"{len(resp)} Trigger Orders cancelled")
except Exception as e:
return Info(success=False, message="Error or no orders to cancel")`
Hello,
J'ai une erreur lors de l'exécution :
Il y a eu une position prise sur MAGICUSDT mais sans stoploss.
--- Execution started at 2024-01-27 20:08:39 --- Pair REN/USDT not found, removing from params... Setting isolated x3 on 21 pairs... Getting data and indicators on 21 pairs... Balance: XXXXXXX USDT Getting open trigger orders... Canceling trigger orders... Getting open orders... Canceling limit orders... Getting live positions... Current position on MAGIC/USDT short - 162.8 ~ 184.71 $ Placing 2 close SL / limit order... Traceback (most recent call last): File "/home/ubuntu/Live-Tools-V2/strategies/envelopes/multi_bitget.py", line 443, in asyncio.run(main()) File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run return loop.run_until_complete(main) File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete return future.result() File "/home/ubuntu/Live-Tools-V2/strategies/envelopes/multi_bitget.py", line 439, in main raise e File "/home/ubuntu/Live-Tools-V2/strategies/envelopes/multi_bitget.py", line 381, in main await asyncio.gather(*tasks_close) # Limit orders when in positions File "/home/ubuntu/./Live-Tools-V2/utilities/bitget_perp.py", line 283, in place_order raise e File "/home/ubuntu/./Live-Tools-V2/utilities/bitget_perp.py", line 265, in place_order resp = await self._session.create_order( File "/home/ubuntu/.local/lib/python3.10/site-packages/ccxt/async_support/bitget.py", line 3918, in create_order response = await self.privateMixPostV2MixOrderPlaceOrder(request) File "/home/ubuntu/.local/lib/python3.10/site-packages/ccxt/async_support/base/exchange.py", line 759, in request return await self.fetch2(path, api, method, params, headers, body, config) File "/home/ubuntu/.local/lib/python3.10/site-packages/ccxt/async_support/base/exchange.py", line 756, in fetch2 return await self.fetch(request['url'], request['method'], request['headers'], request['body']) File "/home/ubuntu/.local/lib/python3.10/site-packages/ccxt/async_support/base/exchange.py", line 243, in fetch self.handle_errors(http_status_code, http_status_text, url, method, headers, http_response, json_response, request_headers, request_body) File "/home/ubuntu/.local/lib/python3.10/site-packages/ccxt/async_support/bitget.py", line 7694, in handle_errors raise ExchangeError(feedback) # unknown message ccxt.base.errors.ExchangeError: bitget {"code":"45117","msg":"Currently holding positions or orders, the margin mode cannot be adjusted","requestTime":1706386168418,"data":null}
Auriez-vous une idée ?? Merci les gars ;-)