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.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 = [] # 本地卖单列表. 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_15m(self): ticker = self.http_client.get_kline(config.symbol,interval="15m",limit=1) if ticker: high_price = float(ticker[0][2]) low_price = float(ticker[0][3]) return low_price, high_price def get_kline_5m(self): ticker = self.http_client.get_kline(config.symbol,interval="5m",limit=1) if ticker: high_price = float(ticker[0][2]) low_price = float(ticker[0][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_buy_order_by_client_id(self,quantity,buy_price,client_order_id): new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY, order_type=OrderType.LIMIT, quantity=quantity, price=buy_price,client_order_id=client_order_id) 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: # 放到卖单列表待处理 self.sell_orders.append(new_sell_order) print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ") else: print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ") 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} ") else: print(f"交易对:{config.symbol} 卖单创建失败 市价卖出数量: {quantity} ") def cancel_single_order(self,cancel_order): order = self.http_client.cancel_order(config.symbol,cancel_order.get('clientOrderId')) if order: print(f"订单撤销 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ") else: print(f"订单撤销失败 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ") 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): """ #网格交易核心逻辑. """ price_stop_to_sell = float(config.price_stop_to_sell) price_stop_to_buy = float(config.price_stop_to_buy) 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) ## 每次准备刷新止盈价的比例,到了这个比例直接刷 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_5m, high_price_in_5m = self.get_kline_5m() # print(f"{config.symbol}:5分钟最低价: {low_price_in_5m}, 5分钟最高价: {high_price_in_5m}") #循环提醒配置不当 if avg_price_5min > price_stop_to_buy or avg_price_5min < price_stop_to_sell: print(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}") self.config_error_counts+=1 #15次循环提醒一次配置不当 if self.config_error_counts%15 == 0: self.config_error_counts = 0 utility.alert(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}") else: self.config_error_counts = 0 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 = [] # 需要删除的卖单 deficit_scroll_map = {} # 滚动止盈的清仓价 buy_order_price_map = {} # 买单的价格 buy_order_sell_map = {} # 买卖单对应关系 # 买单逻辑,检查买单列表成交的情况.一旦成功立即加价卖 # print("当前委托买单:") # print(self.buy_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 #盈利卖单挂 profit_client_order_id = BinanceSpotHttp.get_client_order_id() if self.create_sell_order_by_client_id(quantity, sell_price,profit_client_order_id): print(f"{utility.cn_time()} :交易对:{config.symbol}, 买单 {order_client_id} 成交, 价格: {order_price}, 数量: {order_orig_qty}") # 盈利卖单挂成功的话,删掉本买单 buy_delete_orders.append(buy_order) self.buy_orders.remove(buy_order) # 维护买卖单关系 buy_order_sell_map[order_client_id] = profit_client_order_id #未成交的买单不处理 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: self.buy_orders.remove(delete_order) # 卖单逻辑, 检查卖单成交情况.不做措施 # print("当前委托卖单:") # print(self.sell_orders) 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) 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}") #预估 # 最低卖价大于原卖单定价的止盈比例时候,先删除本卖单,再创建一个更高价的卖单 if ask_price >= order_price * profit_intend: # 先删除本卖单 if self.cancel_open_orders(check_order): # 再创建一个更高价的卖单 new_order_price_profit = order_price * profit_scroll new_order_price_deficit = ask_price * deficit_scroll profit_client_order_id = BinanceSpotHttp.get_client_order_id() profit_sell_order = self.self.create_sell_order_by_client_id(order_orig_qty,new_order_price_profit,profit_client_order_id) if profit_sell_order: 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) self.sell_orders.remove(sell_order) # 本地记录新卖单的止损价格 deficit_scroll_map[profit_client_order_id] = new_order_price_deficit else: 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(f"止盈卖单取消失败:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}") # 当前卖单存在止损价,且最低卖价不大于止损价时候,止损处理掉当前卖单 # 其实所存的止损价是经过滚动止盈产生的,所以还是在盈利 elif deficit_scroll_map.has_key(order_client_id) and ask_price <= deficit_scroll_map[order_client_id]: # 先删除本卖单,挂太高了,卖不出去 if self.cancel_open_orders(check_order): # 市价卖出本订单待卖的币 self.create_sell_order_market(order_orig_qty) 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: 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: print(f"开始创建买单:价格{buy_price} 数量 {quantity} ") buy_client_order_id = BinanceSpotHttp.get_client_order_id() if self.create_buy_order_by_client_id(quantity,buy_price,buy_client_order_id): # 买入成功后记录买单的原价 buy_order_price_map[buy_client_order_id] = buy_price else: print(f"买单{buy_client_order_id}创建失败 数量 {quantity} 价格{buy_price}") else: print(f"买价 {buy_price}大于平均价 {avg_price_5min} 再等等") else: print(f"买价 {buy_price}大于15分钟最高价 {high_price_in_15m} 高位勿买") # 买单数量过多,2min取消一次价格最离谱的买单 elif len(self.buy_orders) >= int(config.max_orders): # 主循环6次 2min更新一次 print(f"当前买单数量达到{config.max_orders},将在{(6 - self.loop_counts % 6)*20}秒后删除一个价格最离谱的买单") if self.loop_counts % 6 == 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): self.buy_orders.remove(impossible_order) 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: self.buy_orders.remove(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} 请处理") print(f"{utility.cn_time()} 第{self.loop_counts}轮循环结束 休息20s")