You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python编写Binance交易算法重复发送市价单问题求解

核心问题原因

1. 无订单执行状态标记,重复触发同信号

当前逻辑仅判断最新K线的action_final值,没有记录上一次已经执行过的信号。1分钟K线的最后一行信号会在整整1分钟内保持同一个值,你每60秒触发一次循环,只要新K线还未生成,最新的action_final就还是上一次的1/-1,自然会重复发单。
你提到的action列不会连续出现1/-1是指所有历史K线的完整序列,但你每次仅取当前最后一个值,这个值会在多个循环周期里重复出现,是连续发单的核心诱因。

2. 浮点数等值判断风险

你用==直接判断浮点数action_final是否等于1/-1,diff()计算、Series转float的过程中可能出现浮点精度误差,比如原本应该是1的值变成0.999999999999999或者1.000000000000002,会导致判断逻辑不符合预期。

3. 无持仓/订单状态前置校验

你没有先查询当前是否已经持有对应仓位、是否有未成交订单,就直接发单,就算信号重复,也没有第二层拦截机制。

4. 交易所接口无异常处理

create_order调用可能因为网络波动、接口限流、余额不足等原因报错,你没有捕获异常也没有确认订单最终状态,可能出现你以为没发单成功实际上已经成交,下一次循环又重复发单的情况。


修复方案

第一步:添加已执行信号标记,避免重复触发

新增变量记录上一次执行的动作,只有当新的信号和上一次执行的动作不同,且信号为1/-1时才发单,同时补全异常处理和订单状态校验:

def bot():
    # 初始化变量记录上一次执行的动作,初始为0(无操作)
    last_executed_action = 0
    while True:
        tick = datetime.datetime.now()
        print(tick)
    
        # 从Binance导入数据,最终输出仅包含收盘价数据点的dataframe 
        candles = client.get_historical_klines("ADAUSDT", Client.KLINE_INTERVAL_1MINUTE, "1 day ago UTC")
        data = pd.DataFrame({'close':np.asarray(candles)[:,4]})
        data['close'] = data['close'].astype(float)

        # 模型生成position_signal逻辑
        data['action'] = data['position_signal'].diff()

        # 用取整替代直接浮点数判断,规避精度问题,改用iloc明确取最后一个值
        action_final = int(round(float(data['action'].iloc[-1])))
        close = float(data['close'].iloc[-1])

        balancebuy = float(client.get_asset_balance(asset='ADA', recvWindow=10000)['free'])
        balancesell = float(client.get_asset_balance(asset='USDT', recvWindow=10000)['free'])
        maxBuy = round(balancesell / close * .99)
        
        # 新增判断:当前信号和上一次执行的信号不同才执行
        if action_final == 1 and last_executed_action != 1:
            # 新增异常捕获和订单状态确认
            try:
                order = client.create_order(
                    symbol='ADAUSDT',
                    side=client.SIDE_BUY,
                    type=client.ORDER_TYPE_MARKET,
                    quantity=maxBuy,
                    recvWindow=10000) 
                # 只有确认订单完全成交才更新执行标记
                if order['status'] == 'FILLED':
                    last_executed_action = 1
                    print('Buy filled.')
            except Exception as e:
                print(f"Buy order failed: {str(e)}")

        elif action_final == -1 and last_executed_action != -1:
            try:
                order = client.create_order(
                    symbol='ADAUSDT',
                    side=client.SIDE_SELL,
                    type=client.ORDER_TYPE_MARKET,
                    quantity=round(balancebuy - 0.1),
                    recvWindow=10000) 
                if order['status'] == 'FILLED':
                    last_executed_action = -1
                    print('Sell filled.')
            except Exception as e:
                print(f"Sell order failed: {str(e)}")

        else:
            print('No trade.') 
            
        time.sleep(60.0 - ((time.time() - starttime) % 60.0))
        
bot()

第二步:新增持仓校验作为第二重拦截

发单前额外校验当前持仓状态,比如买单前确认ADA余额小于0.1(空仓状态),卖单前确认ADA余额大于1(持仓状态),进一步避免重复发单。

第三步:优化K线数据校验

拉取K线后先校验最新的K线是否已经闭合,避免使用还在生成中的未完成K线的信号,防止信号来回变动导致误发单。


内容的提问来源于stack exchange,提问作者jack sharp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:15:02