TAKE_PROFIT_PERCENT = 0.025  # 2.5%
TIMEFRAME_30M = '30m'
TIMEFRAME_5M = '5m'


async def main():
    client = await AsyncClient.create(API_KEY, API_SECRET)
    try:
        # 设置杠杆
        for symbol in SYMBOLS:
            await client.futures_change_leverage(symbol=symbol, leverage=LEVERAGE)

        while True:
            tasks = [handle_symbol(client, symbol) for symbol in SYMBOLS]
            await asyncio.gather(*tasks)
            await asyncio.sleep(60)  # 每5分钟检查一次
    finally:
        await client.close_connection()


async def handle_symbol(client, symbol):
    global previous_sar, previous_close, current_sar, current_close
    try:
        # 获取30分钟K线数据
        klines_30m = await client.futures_klines(symbol=symbol, interval=TIMEFRAME_30M, limit=100)
        df_30m = pd.DataFrame(klines_30m, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume',
                                                   'close_time', 'quote_asset_volume', 'number_of_trades',
                                                   'taker_buy_base_asset_volume', 'taker_buy_quote_asset_volume',
                                                   'ignore'])
        df_30m['close'] = df_30m['close'].astype(float)

        # 获取5分钟K线数据
        klines_5m = await client.futures_klines(symbol=symbol, interval=TIMEFRAME_5M, limit=500)
        df_5m = pd.DataFrame(klines_5m, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume',
                                                 'close_time', 'quote_asset_volume', 'number_of_trades',
                                                 'taker_buy_base_asset_volume', 'taker_buy_quote_asset_volume',
                                                 'ignore'])
        df_5m['open'] = df_5m['open'].astype(float)
        df_5m['high'] = df_5m['high'].astype(float)
        df_5m['low'] = df_5m['low'].astype(float)
        df_5m['close'] = df_5m['close'].astype(float)

        # 计算30分钟MACD的DIF
        macd = ta.macd(df_30m['close'])
        dif = macd['MACD_12_26_9'].iloc[-1]

        # 打印30分钟的DIF是大于0还是小于0
        if dif > 0:
            print(f"{symbol} 30分钟DIF大于0: {dif}")
        else:
            print(f"{symbol} 30分钟DIF小于0: {dif}")

        # 计算5分钟SAR
        psar = ta.psar(df_5m['high'], df_5m['low'], step=0.02, max_step=0.2)
        df_5m['sar'] = psar.iloc[:, 0]  # PSARl_0.02_0.2
        df_5m['sar_direction'] = psar.iloc[:, 1]  # PSARs_0.02_0.2

        # 处理可能的NaN值
        df_5m['sar'] = df_5m['sar'].fillna(method='ffill')

        current_sar = df_5m['sar'].iloc[-1]
        previous_sar = df_5m['sar'].iloc[-2]
        current_close = df_5m['close'].iloc[-1]
        previous_close = df_5m['close'].iloc[-2]
        current_high = df_5m['high'].iloc[-1]
        current_low = df_5m['low'].iloc[-1]
        previous_high = df_5m['high'].iloc[-2]
        previous_low = df_5m['low'].iloc[-2]

        # 打印前一根K线和当前K线的SAR位置和值
        print(f"{symbol} SAR信息:")
        print(f"前一根K线 - 高: {previous_high}, 低: {previous_low}, 收盘: {previous_close}, SAR: {previous_sar}")
        print(f"当前K线 - 高: {current_high}, 低: {current_low}, 收盘: {current_close}, SAR: {current_sar}")

        # 判断并打印SAR在K线上方还是下方
        if previous_sar < previous_low:
            print(f"前一根K线SAR在K线下方: SAR值 {previous_sar}")
        elif previous_sar > previous_high:
            print(f"前一根K线SAR在K线上方: SAR值 {previous_sar}")
        else:
            print(f"前一根K线SAR在K线内: SAR值 {previous_sar}")

        if current_sar < current_low:
            print(f"当前K线SAR在K线下方: SAR值 {current_sar}")
        elif current_sar > current_high:
            print(f"当前K线SAR在K线上方: SAR值 {current_sar}")
        else:
            print(f"当前K线SAR在K线内: SAR值 {current_sar}")

        # 获取当前UTC时间
        current_utc = datetime.utcnow()
        # 转换为北京时间（UTC+8）
        beijing_time = current_utc + timedelta(hours=8)
        time_str = beijing_time.strftime("%Y-%m-%d %H:%M:%S")

        # 更精确地判断SAR的位置变化
        previous_sar_below = previous_sar <= previous_low
        previous_sar_above = previous_sar >= previous_high
        current_sar_below = current_sar <= current_low
        current_sar_above = current_sar >= current_high

        # 获取仓位信息
        position_info = await client.futures_position_information(symbol=symbol)
        position_amt = float(position_info[0]['positionAmt'])

        # 判断做多条件
        if dif > 0 and previous_sar_above and not current_sar_above:
            print(f"[{time_str}] {symbol} 满足做多条件：DIF: {dif}, 前一根SAR在上方: {previous_sar}, 当前SAR不在上方: {current_sar}")

            if position_amt == 0:
                await open_position(client, symbol, "LONG")
        # 判断做空条件
        elif dif < 0 and previous_sar_below and not current_sar_below:
            print(f"[{time_str}] {symbol} 满足做空条件：DIF: {dif}, 前一根SAR在下方: {previous_sar}, 当前SAR不在下方: {current_sar}")

            if position_amt == 0:
                await open_position(client, symbol, "SHORT")


        # 已有仓位，检查止盈止损
        elif position_amt != 0:
            await manage_position(client, symbol, position_amt)
        else:
            print(f"{symbol} 不满足交易条件")

            # 打印更详细的信息用于调试
            print(f"[{time_str}] {symbol} SAR信息:")
            # print(f"前一根K线 - 高: {previous_high}, 低: {previous_low}, 收盘: {previous_close}, SAR: {previous_sar}")
            # print(f"当前K线 - 高: {current_high}, 低: {current_low}, 收盘: {current_close}, SAR: {current_sar}")
            print(f"SAR位置判断: 前一根SAR - 上方: {previous_sar_above}, 下方: {previous_sar_below}")
            print(f"SAR位置判断: 当前SAR - 上方: {current_sar_above}, 下方: {current_sar_below}")
            print(f"30分钟DIF: {dif}")

    except Exception as e:
        logging.error(f"处理交易对{symbol}时出错: {e}")


async def open_position(client, symbol, side):
    try:
        # 获取当前订单簿
        depth = await client.futures_order_book(symbol=symbol, limit=10)
        if side == "LONG":
            price = float(depth['asks'][3][0])  # 买入，取第4个最优价
        else:
            price = float(depth['bids'][3][0])  # 卖出，取第4个最优价

        # 计算下单数量
        symbol_info = await client.futures_exchange_info()
        info = next(filter(lambda x: x['symbol'] == symbol, symbol_info['symbols']))
        lot_size = next(filter(lambda f: f['filterType'] == 'LOT_SIZE', info['filters']))
        step_size = float(lot_size['stepSize'])
        quantity = round_step_size(TRADE_AMOUNT * LEVERAGE / price, step_size)

        # 下限价单开仓
        order = await client.futures_create_order(
            symbol=symbol,
            side='BUY' if side == "LONG" else 'SELL',
            type='LIMIT',
            price=price,
            quantity=quantity,
            timeInForce='GTC')

        logging.info(f"[{get_beijing_time()}] {symbol} 开仓 {side}，价格：{price}，数量：{quantity}")
        logging.info(f"[{get_beijing_time()}] {symbol} 开仓订单：{order}")

        # 设置止盈（限价单）
        take_profit_price = round_step_size(
            price * (1 + TAKE_PROFIT_PERCENT if side == "LONG" else 1 - TAKE_PROFIT_PERCENT), step_size)
        tp_order = await client.futures_create_order(
            symbol=symbol,
            side='SELL' if side == "LONG" else 'BUY',
            type='LIMIT',
            price=take_profit_price,
            quantity=quantity,
            reduceOnly='true',
            timeInForce='GTC')

        logging.info(f"[{get_beijing_time()}] {symbol} 设置止盈单，价格：{take_profit_price}")
        logging.info(f"[{get_beijing_time()}] {symbol} 止盈订单：{tp_order}")

        # 获取入场前一根K线的最高/最低价
        klines = await client.futures_klines(symbol=symbol, interval=TIMEFRAME_5M, limit=2)
        previous_kline = klines[0]
        high_price = float(previous_kline[2])
        low_price = float(previous_kline[3])

        # 设置止损（市价单）
        stop_loss_price = low_price if side == "LONG" else high_price
        sl_order = await client.futures_create_order(
            symbol=symbol,
            side='SELL' if side == "LONG" else 'BUY',
            type='STOP_MARKET',
            stopPrice=stop_loss_price,
            quantity=quantity,
            reduceOnly='true')

        logging.info(f"[{get_beijing_time()}] {symbol} 设置止损单，触发价格：{stop_loss_price}")
        logging.info(f"[{get_beijing_time()}] {symbol} 止损订单：{sl_order}")

    except Exception as e:
        logging.error(f"[{get_beijing_time()}] 开仓时发生错误：{e}")

def get_beijing_time():
    return (datetime.utcnow() + timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S")

def round_step_size(quantity, step_size):
    return round(quantity / step_size) * step_size

async def manage_position(client, symbol, position_amt):
    try:
        # 检查仓位盈亏，是否达到止盈止损条件
        # 在此可以根据需要添加更多逻辑
        pass
    except Exception as e:
        logging.error(f"管理仓位时发生错误：{e}")

程序入场但是没设置止盈和止损，
入场：采用限价单，设置为对己方最优价第4个，是对自己最优

止盈：采用限价单，设置为涨跌2.5%

止损：采用市价单，设置为入场前一根k线的最高/最低点价