from binance import BinanceSpotHttp, OrderStatus, OrderType, OrderSide from utils import config from utils import round_to from utils import utility class BinanceTrader(object): def __init__(self): """ :param api_key: :param secret: :param trade_type: 交易的类型, only support future and spot. """ self.loop_counts = 0 self.config_error_counts = 0 #止损价配置不当,提示次数 self.sleep_time = config.sleep_time #循环间隔秒数 self.cancel_time = config.cancel_time #取消订单周期 self.http_client = BinanceSpotHttp(api_key=config.api_key, secret=config.api_secret, proxy_host=config.proxy_host, proxy_port=config.proxy_port) self.buy_orders = [] # 本地买单列表. self.sell_orders = [] # 本地卖单列表. self.deficit_scroll_map = {} # 滚动止盈的清仓价 def get_avg_price_5min(self): #获取5分钟内的平均价 ticker = self.http_client.get_avg_price_5min(config.symbol) price = 0 if ticker: price = float(ticker.get('price', 0)) return price def get_latest_price(self): #获取最新价格 ticker = self.http_client.get_latest_price(config.symbol) price = 0 if ticker: price = float(ticker.get('price', 0)) return price def get_price_change_percent_24h(self): #获取24h内的价格变化百分比数据 ticker = self.http_client.get_price_info_24h(config.symbol) priceChangePercent = 0 if ticker: priceChangePercent = float(ticker.get('priceChangePercent', 0)) return priceChangePercent def get_bid_ask_price(self): #最高买价 最低卖价 ticker = self.http_client.get_ticker(config.symbol) bid_price = 0 ask_price = 0 if ticker: bid_price = float(ticker.get('bidPrice', 0)) ask_price = float(ticker.get('askPrice', 0)) return bid_price, ask_price def get_depth(self,limit): ticker = self.http_client.get_order_book(config.symbol,limit=limit) if ticker: #high_price = float(ticker[0][2]) print(ticker) return 123 def get_kline(self,interval): ticker = self.http_client.get_kline(config.symbol,interval=interval,limit=1) if ticker: high_price = float(ticker[0][2]) low_price = float(ticker[0][3]) return low_price, high_price # 获取倒数第二个k线数据 def get_kline_pre4(self,interval): ticker = self.http_client.get_kline(config.symbol,interval=interval,limit=4) if ticker: high_price = float(ticker[3][2]) low_price = float(ticker[3][3]) return low_price, high_price def create_buy_order(self,quantity,buy_price): new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY, order_type=OrderType.LIMIT, quantity=quantity, price=buy_price) if new_buy_order: # 买单维护到买单列表待处理 self.buy_orders.append(new_buy_order) print(f"买单创建 价格: {buy_price}, 数量: {quantity} ") else: print(f"买单创建失败 价格: {buy_price}, 数量: {quantity} ") def create_sell_order(self,quantity,sell_price): new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL, order_type=OrderType.LIMIT, quantity=quantity, price=sell_price) if new_sell_order: # 放到卖单列表待处理 self.sell_orders.append(new_sell_order) print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ") else: print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ") def create_sell_order_by_client_id(self,quantity,sell_price,client_order_id): new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL, order_type=OrderType.LIMIT, quantity=quantity, price=sell_price,client_order_id=client_order_id) if new_sell_order is not None: # 放到卖单列表待处理 self.sell_orders.append(new_sell_order) print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ") return True else: print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ") return False def create_sell_order_market(self,quantity): new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL, order_type=OrderType.MARKET, quantity=quantity) if new_sell_order: # 市价订单必定成功 self.sell_orders.append(new_sell_order) print(f"交易对:{config.symbol} 市价卖出数量: {quantity} ") return True else: print(f"交易对:{config.symbol} 卖单创建失败 市价卖出数量: {quantity} ") return False def cancel_single_order(self,cancel_order): order = self.http_client.cancel_order(config.symbol,cancel_order.get('clientOrderId')) if order is None: utility.alert(f"订单撤销失败 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ") return False else: print(f"订单撤销成功 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ") return True def cancel_open_orders(self): open_orders_list = self.http_client.get_open_orders(config.symbol) for open_order in open_orders_list: if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value: #只取消本客户端创建的买单 if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'): self.cancel_single_order(open_order) print(f"买单{open_order.get('clientOrderId')}已取消取消") def sync_open_orders(self): open_orders_list = self.http_client.get_open_orders(config.symbol) for open_order in open_orders_list: #只同步本客户端创建的订单 if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'): if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value: self.buy_orders.append(open_order) print(f"买单{open_order.get('clientOrderId')}同步到本地") if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.SELL.value: self.sell_orders.append(open_order) print(f"卖单{open_order.get('clientOrderId')}同步到本地") #网格交易核心逻辑. def grid_trader(self): """ #网格交易核心逻辑. """ quantity = round_to(float(config.quantity), float(config.min_qty)) ## quantity是config.quantity到config.min_qty的精度转换 profit_scroll = float(config.profit_scroll) ## 每次刷新止盈价的比例 deficit_scroll = float(config.deficit_scroll) ## 每次刷新止损价的比例 profit_intend = float(config.profit_intend) ## 每次准备刷新止盈价的比例,到了这个比例直接刷 gap_percent= float(config.gap_percent) ## 卖单提价比例 self.loop_counts+=1 print(f"{utility.cn_time()} 第{self.loop_counts}轮循环开始") bid_price, ask_price = self.get_bid_ask_price() print(f"{config.symbol}:最高买价bid_price: {bid_price}, 最低卖价ask_price: {ask_price}") avg_price_5min = float(self.get_avg_price_5min()) #latest_price = self.get_latest_price() #5分钟k线 15分钟k线 low_price_in_15m, high_price_in_15m = self.get_kline("15m") print(f"{config.symbol}:15分钟最低价: {low_price_in_15m}, 15分钟最高价: {high_price_in_15m}") low_price_in_4h, high_price_in_4h = self.get_kline("4h") low_price_pre_in_4h, high_price_pre_in_4h = self.get_kline_pre4("2h") print(f"low_price_in_4h: {low_price_in_4h}") print(f"high_price_in_4h: {high_price_in_4h}") print(f"low_price_pre_in_4h: {low_price_pre_in_4h}") print(f"high_price_pre_in_4h: {high_price_pre_in_4h}") # 取波峰波谷的中间值 peak_price = high_price_in_4h if high_price_in_4h <= high_price_pre_in_4h else high_price_pre_in_4h bottom_price = low_price_in_4h if low_price_in_4h >= low_price_pre_in_4h else low_price_pre_in_4h delta_price_in_4h = float(peak_price)-float(bottom_price) price_stop_to_sell = float(bottom_price) + delta_price_in_4h * 0.1 price_stop_to_buy = float(peak_price) - delta_price_in_4h * 0.8 print(f"high_price_in_4h_4h: {peak_price}") print(f"low_price_in_4h_4h: {bottom_price}") print(f"价格上限: {price_stop_to_buy}") print(f"价格下限: {price_stop_to_sell}") # price_stop_to_sell = float(config.price_stop_to_sell) # price_stop_to_buy = float(config.price_stop_to_buy) self.buy_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价. self.sell_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价. buy_delete_orders = [] # 需要删除的买单 sell_delete_orders = [] # 需要删除的卖单 # 买单逻辑,检查买单列表成交的情况.一旦成功立即加价卖 print("-------------买单逻辑-----------------") for buy_order in self.buy_orders: check_order = self.http_client.get_order(buy_order.get('symbol', config.symbol),client_order_id=buy_order.get('clientOrderId')) if check_order: order_status = check_order.get('status') order_price = check_order.get('price') order_orig_qty = check_order.get('origQty') order_client_id = buy_order.get('clientOrderId') #取消状态的买单 不管 if order_status == OrderStatus.CANCELED.value: buy_delete_orders.append(buy_order) print(f"买单{order_client_id}状态为取消: {order_status}") #成交状态买单,需要处理 elif order_status == OrderStatus.FILLED.value: print(f"成交状态的买单: {order_client_id} 成交时间: {utility.cn_time()} 价格: {order_price} 数量: {order_orig_qty}") # 买单成交后,提高价格,挂盈利卖单 sell_price = round_to(float(order_price) * (1 + float(config.gap_percent)), float(config.min_price)) if 0 < sell_price < ask_price: # 防止价格小于最低卖价ask_price sell_price = round_to(ask_price, float(config.min_price)) #如果卖价小于设定的持仓价格price_stop_to_sell,将卖价提高至持仓价,才交易 if 0 < sell_price < price_stop_to_sell: print(f"卖价{sell_price} 小于持仓价{price_stop_to_sell} ,已调整为持仓价交易") sell_price = price_stop_to_sell #盈利卖单挂 if self.create_sell_order(quantity, sell_price): print(f"{utility.cn_time()} :交易对:{config.symbol}, 买单 {order_client_id} 成交, 价格: {order_price}, 数量: {order_orig_qty}") # 盈利卖单挂成功的话,删掉本买单 buy_delete_orders.append(buy_order) if buy_order in self.buy_orders: self.buy_orders.remove(buy_order) #未成交的买单不处理 elif order_status == OrderStatus.NEW.value: print(f"未成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}") # 部分成交的买单 提示下就行了 elif order_status == OrderStatus.PARTIALLY_FILLED.value: print(f"部分成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}") #异常状态买单 else: utility.alert(f"交易对:{config.symbol}, 时间: {utility.cn_time()}, 买单{order_client_id}失败{order_status}") # 过期或者拒绝的订单删除掉. for delete_order in buy_delete_orders: if delete_order in self.buy_orders: self.buy_orders.remove(delete_order) # 卖单逻辑, 检查卖单成交情况 print("--------------卖单逻辑----------------") for sell_order in self.sell_orders: check_order = self.http_client.get_order(sell_order.get('symbol', config.symbol),client_order_id=sell_order.get('clientOrderId')) if check_order: order_status = check_order.get('status') order_price = check_order.get('price') order_orig_qty = check_order.get('origQty') order_client_id = sell_order.get('clientOrderId') #卖单状态为取消 不管 if order_status == OrderStatus.CANCELED.value: sell_delete_orders.append(sell_order) print(f"卖单{order_client_id}状态为取消: {order_status}") #卖单状态为成交 elif order_status == OrderStatus.FILLED.value: print(f"卖单{order_client_id}成交时间: {utility.cn_time()}, 价格: {order_price}, 数量: {order_orig_qty}") #第一遍才发通知 if sell_order not in sell_delete_orders: utility.alert(f"卖单成交: {utility.cn_time()} {order_client_id}, 交易对:{config.symbol}, 价格: {order_price}, 数量: {order_orig_qty}") # 卖单成交,不再维护该卖单状态 sell_delete_orders.append(sell_order) if sell_order in self.sell_orders: self.sell_orders.remove(sell_order) # 新挂的卖单 创建移动止盈策略 elif order_status == OrderStatus.NEW.value: print(f"还没成交的卖单:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}") print(f"当前最低卖价: {ask_price}") orig_buy_price = float(order_price) / (float(gap_percent) + 1) print(f"预估本单的买入价格: {orig_buy_price}") triger_price = float(order_price) * float(profit_intend) print(f"移动止盈触发价格: {triger_price}") if ask_price >= triger_price: print("最低卖价大于移动止盈触发价格,先删除本卖单,再创建一个更高价的卖单") if self.cancel_single_order(check_order): # 删除成功 再创建一个更高价的卖单 new_order_price_profit = float(order_price) * float(profit_scroll) new_order_price_deficit = float(ask_price) * float(deficit_scroll) new_order_price_profit = round_to(new_order_price_profit, float(config.min_price)) new_order_price_deficit = round_to(new_order_price_deficit, float(config.min_price)) print(f"new_order_price_profit: {new_order_price_profit}") print(f"new_order_price_deficit: {new_order_price_deficit}") profit_client_order_id = self.http_client.get_client_order_id() profit_sell_order = self.create_sell_order_by_client_id(order_orig_qty, new_order_price_profit, profit_client_order_id) if profit_sell_order: print("----------------移动止盈触发成功-------yyyyyyyyyyyyyyyyyyyyyyyyyyyy------") print( f"{utility.cn_time()} :卖单 {order_client_id}滚动止盈触发新卖单{profit_client_order_id},交易对:{config.symbol},新期望价格: {new_order_price_profit}, 数量: {order_orig_qty}") # 移动止盈卖单挂成功的话,本地不再维护原卖单 sell_delete_orders.append(sell_order) if sell_order in self.sell_orders: self.sell_orders.remove(sell_order) # 本地记录新卖单的止损价格 self.deficit_scroll_map[profit_client_order_id] = new_order_price_deficit else: print("----------------移动止盈触发失败------eeeeeeeeeeeeeeeeeeeeeeeeeeee-------") print( f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ") utility.alert( f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ") else: print("原买单删除失败") # 当前卖单存在止损价,且最低卖价不大于止损价时候,止损处理掉当前卖单 # 其实所存的止损价是经过滚动止盈产生的,所以还是在盈利 # 当前卖价要大于买单价格才可以 elif order_client_id in self.deficit_scroll_map and ask_price <= self.deficit_scroll_map[order_client_id] and ask_price > orig_buy_price: # 先删除本卖单,挂太高了,卖不出去 if self.cancel_open_orders(check_order): # 市价卖出本订单待卖的币 self.create_sell_order_market(order_orig_qty) print("----------移动止损成功--------------") else: print(f"止损卖单取消失败:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}") # 部分成交的卖单 提示下就行了 elif order_status == OrderStatus.PARTIALLY_FILLED.value: print(f"部分成交的卖单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}") else: utility.alert(f"挂卖单失败 交易对:{config.symbol}, 时间: {utility.cn_time()}, {order_status}") #处理过期或者拒绝的订单,不在维护到本地 for delete_order in sell_delete_orders: if delete_order in self.sell_orders: self.sell_orders.remove(delete_order) # 买单数量未满 并且卖单也没满时候 usdt没有积压 可以新建买单 if len(self.buy_orders) < int(config.max_orders) and len(self.sell_orders) < int(config.max_sell_orders): print("买单数量未满,卖单也没积压,开始创建一个新买单:") print("------------------------------") if bid_price > 0: buy_price = round_to(bid_price * (1 - float(config.gap_percent)), float(config.min_price)) ##如果买价大于设定的抛仓价格price_stop_to_buy,将买价降低至抛仓价,才交易 if buy_price > price_stop_to_buy > 0: buy_price = price_stop_to_buy #动态价格保护,如果买价不高于15分钟k线最高值,说明价格在跌,适合买 if buy_price <= high_price_in_15m : # 如果价格不大于5分钟内的平均价 说明价格还可以,能继续买入 if buy_price <= avg_price_5min: buy_price = round_to(buy_price,float(config.min_price)) print(f"开始创建买单:价格{buy_price} 数量 {quantity} ") self.create_buy_order(quantity,buy_price) else: print(f"买价 {buy_price}大于平均价 {avg_price_5min} 再等等") else: print(f"买价 {buy_price}大于15分钟最高价 {high_price_in_15m} 高位勿买") # 买单数量过多,cancel_time 取消一次价格最离谱的买单 elif len(self.buy_orders) >= int(config.max_orders): # cancel_time更新一次 主循环cancel_time/gcd_time次 cancel_period=self.cancel_time/self.sleep_time print(f"当前买单数量达到{config.max_orders},将在{(cancel_period - self.loop_counts % cancel_period)*self.sleep_time}秒后删除一个价格最离谱的买单") if self.loop_counts % cancel_period == 0: print(f"开始删除价格最离谱的买单:") print("------------------------------") # 最离谱到最接近 self.buy_orders.sort(key=lambda x: abs(float(x['price'])-float(avg_price_5min)), reverse=True) impossible_order=self.buy_orders[0] if self.cancel_single_order(impossible_order): if impossible_order in self.buy_orders: self.buy_orders.remove(impossible_order) buy_delete_orders.append(impossible_order) print(f"买单列表已满 价格离谱的买单{impossible_order.get('clientOrderId')}删除 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ") else: print(f"买单列表已满 价格离谱的买单{impossible_order.get('clientOrderId')}删除失败 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ") for fade_order in self.buy_orders: if float(fade_order.get('price')) > high_price_in_15m or float(fade_order.get('price')) < low_price_in_15m: if fade_order in self.buy_orders: self.buy_orders.remove(fade_order) buy_delete_orders.append(fade_order) print(f"取消价格未在15m k线的买单{fade_order.get('clientOrderId')} 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ") # 没有卖单的时候 暂时先不创建卖单,防止利润计算错误 if len(self.sell_orders) <= 0: print(f"当前没有卖单,请注意查看{config.symbol}余额") print("------------------------------") #卖单过多,暂不处理 elif len(self.sell_orders) > int(config.max_orders): print("卖单过多:") print("------------------------------") print(f"交易对{config.symbol}卖单较多,大于个{config.max_orders} 请处理") #集中处理 buy_delete_orders sell_delete_orders for buy_order in buy_delete_orders: if self.cancel_single_order(buy_order): if buy_order in buy_delete_orders: buy_delete_orders.remove(buy_order) for sell_order in sell_delete_orders: if self.cancel_single_order(sell_order): if sell_order in sell_delete_orders: sell_delete_orders.remove(sell_order) print(f"{utility.cn_time()} 第{self.loop_counts}轮循环结束 休息{self.sleep_time}s")