همه این کدها رو مرتب و یکجور بازنویسی کن
import time, requests, urllib.parse, hashlib, hmac, json, threading
from datetime import datetime
import pandas as pd


class apiToobit:
    def __init__(self, api_key: str, secret_key: str, user: str):
        self.api_key = api_key
        self.secret_key = secret_key
        self.user = user
        self.APIURL = 'https://api.toobit.com'
        self.HEADER = {"X-BB-APIKEY": api_key, "Content-Type": "application/x-www-form-urlencoded"}

    def _sign(self, data: str):
        return hmac.new(self.secret_key.encode(), data.encode(), hashlib.sha256).hexdigest()

    def _send_request(self, action: str, method: str, path: str, params: dict):
        try:
            params = dict(sorted(params.items(), key=lambda x: x[0]))
            data = "&".join(f"{key}={value}" for key, value in sorted(params.items()))
            signature = self._sign(data)
            if signature:
                url = f"{self.APIURL}{path}"
                response = requests.request(
                    method,
                    url,
                    data=data,
                    headers=self.HEADER,
                    params={"signature": signature,  **params} if method=='GET' else {"signature": signature}
                )

            if response.status_code == 200:
                return response.json()
            else:
                print(f"Error in {action}: {response.text}")
                return None
        except Exception as e:
            print(f"Unexpected error in {action}: {str(e)}")
            return None

    def create_listen_key(self):
        params = {
            "timestamp": int(time.time() * 1000),
            "recvWindow": 10000
        }
        return self._send_request('create_listen_key', 'POST', '/api/v1/listenKey', params)

    def keepalive_listen_key(self, listenKey: str):
        params = {
            "listenKey": listenKey,
            "timestamp": int(time.time() * 1000),
            "recvWindow": 10000
        }
        return self._send_request('keepalive_listen_key', 'PUT', '/api/v1/listenKey', params)

    def close_listen_key(self, listenKey: str):
        params = {
            "listenKey": listenKey,
            "timestamp": int(time.time() * 1000),
            "recvWindow": 10000
        }
        return self._send_request('close_listen_key', 'DELETE', '/api/v1/listenKey', params)

    def set_leverage(self, sym: str, leverage: int):
        params = {
            "symbol": f"{sym.upper()}-SWAP-USDT",
            "leverage": leverage,
            "timestamp": int(time.time() * 1000),
        }
        return self._send_request("set_leverage", "POST", "/api/v1/futures/leverage", params)

    def set_marginType(self, sym: str, marginType: str):
        params = {
            'symbol': f'{sym.upper()}-SWAP-USDT',
            'marginType': marginType.upper(),
            'timestamp': int(time.time() * 1000)
        }
        return self._send_request('set_marginType', 'POST', '/api/v1/futures/marginType', params)

    def get_last_price(self, sym: str):
        params = {"symbol": f"{sym.upper()}-SWAP-USDT"}
        response = self._send_request("get_last_price", "GET", "/quote/v1/markPrice", params)
        return float(response["price"]) if response else None

    def get_candle_data(self, sym: str, interval: str = '1h', limit: int = 1000):
        params = {
            "symbol": f"{sym.upper()}-SWAP-USDT",  # Symbol for the pair
            "interval": interval,  # Interval (e.g., 1m, 5m, 1h, 1d, 1w)
            "limit": limit,  # Number of requested candlesticks
            "timestamp": int(time.time() * 1000)
        }
        response = self._send_request("get_candle_data", "GET", "/quote/v1/klines", params)
        if not response:
            print("Error: Failed to fetch candlestick data.")
            return None

        try:
            candle_data = []
            for candle in response:
                candle_data.append({
                    "timestamp": datetime.fromtimestamp(candle[0] / 1000).strftime("%Y-%m-%d %H:%M:%S"),  # Human-readable timestamp
                    "open": float(candle[1]),
                    "high": float(candle[2]),
                    "low": float(candle[3]),
                    "close": float(candle[4]),
                    "volume": float(candle[5])
                })
            return candle_data

        except Exception as e:
            print(f"Error while parsing candlestick data: {str(e)}")
            return None
        
    def get_user_balance(self):
        params = {"timestamp": int(time.time() * 1000)}
        response = self._send_request("get_user_balance", "GET", "/api/v1/futures/balance", params)
        return float(response[0]["availableBalance"]) if response else None

    def calculate_quantity(self, sym: str, volume_type: str, volume: float, leverage: int):
        last_price = self.get_last_price(sym)
        account_balance = self.get_user_balance()
        quantity = None
        if volume_type.lower() == "percent":
            volume = (volume * leverage * account_balance / 100)
        elif volume_type.lower() == "fixed":
            volume = volume * leverage
        
        if last_price:
            quantity = round(volume / last_price, 0)
        return quantity

    def open_position(self, sym: str, position_side: str, order_type: str, leverage: int,
                      volume: float, volume_type: str, price: float = None, tp_sl_levels: list = None):
        try:
            # Set leverage for the symbol
            leverage_set = self.set_leverage(sym, leverage)
            if not leverage_set:
                raise ValueError("Failed to set leverage")

            # Calculate quantity based on account balance and position details
            quantity = self.calculate_quantity(sym, volume_type, volume, leverage)
            
            # Open the position
            params = {
                "symbol": f"{sym.upper()}-SWAP-USDT",
                "side": "BUY_OPEN" if position_side.upper() == "LONG" else "SELL_OPEN",
                "type": "LIMIT" if order_type.lower() == "limit" else "MARKET",
                "priceType": "INPUT" if order_type.lower() == "limit" else "MARKET",
                "quantity": quantity,
                "price": price,
                "newClientOrderId": f"OPEN_{position_side.upper()}/{sym.upper()}-{self.user}-{int(time.time() * 1000)}",
                "timestamp": int(time.time() * 1000),
            }

            response = self._send_request("open_position", "POST", "/api/v1/futures/order", params)
            if not response:
                raise ValueError("Failed to open position")

            # Set take-profit/stop-loss levels if provided
            if tp_sl_levels:
                self.set_multi_tp_sl(sym, position_side, tp_sl_levels)

            return response
        except Exception as e:
            print(f"Error while opening position: {str(e)}")
            return None

    def set_multi_tp_sl(self, sym: str, position_side: str, levels: list):
        responses = []
        for level in levels:
            params = {
                "symbol": f"{sym.upper()}-SWAP-USDT",
                "side": "SELL_CLOSE" if position_side.upper() == "LONG" else "BUY_CLOSE",
                "type": "STOP" if level["type"].upper() == "SL" else "LIMIT",
                "priceType": "MARKET" if level["type"].upper() == "SL" else "INPUT",
                "quantity": level["quantity"],
                "price": level.get("price"),
                "stopPrice": level.get("price") if level["type"].upper() == "SL" else None,
                "newClientOrderId": f"{level['type'].upper()}_{int(time.time() * 1000)}",
                "timestamp": int(time.time() * 1000),
            }
            responses.append(self._send_request("set_multi_tp_sl", "POST", "/api/v1/futures/order", params))
        return responses

    def close_position(self, sym: str, position_side: str, quantity: float):
        params = {
            "symbol": f"{sym.upper()}-SWAP-USDT",
            "side": "SELL_CLOSE" if position_side.upper() == "LONG" else "BUY_CLOSE",
            "type": "LIMIT",  # Must use LIMIT with priceType=MARKET
            "priceType": "MARKET",
            "quantity": quantity,
            "timestamp": int(time.time() * 1000),
            "newClientOrderId": f"CLOSE_{position_side.upper()}/{sym.upper()}-{int(time.time() * 1000)}"
        }
        return self._send_request("close_position", "POST", "/api/v1/futures/order", params)