def get_account_balance(symbol=CoinSymbol.Btcusdt): try: request_client = RequestClient(api_key=g_api_key, secret_key=g_secret_key) account_balance_list = request_client.get_account_balance() if account_balance_list and len(account_balance_list): for account in account_balance_list: if account.account_type == AccountType.MARGIN and account.subtype == symbol.symbol: if account.balances and len(account.balances): for balance in account.balances: if balance.currency == CoinSymbol.Btcusdt.coin and balance.balance_type == "trade": balance_info.coin = balance.balance if balance.currency == CoinSymbol.Btcusdt.cash and balance.balance_type == "trade": balance_info.cash = balance.balance except Exception as e: print(e) print("retrying in 1s") time.sleep(1) return get_account_balance()
from huobi import RequestClient from huobi.constant.test import * from huobi.base.printobject import * from huobi.model import Account request_client = RequestClient(api_key=g_api_key, secret_key=g_secret_key) account_balance_list = request_client.get_account_balance() if account_balance_list and len(account_balance_list): for account in account_balance_list: print("======= ID", account.id, "=======") print("Account Status", account.account_state) print("Account Type", account.account_type) print("Subtype", account.subtype) if account.balances and len(account.balances): for balance in account.balances: print("\tBalance Currency", balance.currency) print("\tBalance Type", balance.balance_type) print("\tBalance", balance.balance) print() print()
class KeepBalanceStrategy(BaseStrategy, MailHandler): """ 动态平衡策略 """ def __init__(self): BaseStrategy.__init__(self) self.request_client = RequestClient( api_key=self.get_config_value("huobi", "api_key"), secret_key=self.get_config_value("huobi", "secret_key")) self.strategy = 'KeepBalance' def signal(self): balance_dict = self.get_account_balance() for key, value in enumerate(balance_dict): if float(balance_dict[value]["amount"]) * 1.03 < float( balance_dict[value]["dollar"]): self.buy(value, amount=balance_dict[value]["amount"], dollar=balance_dict[value]["dollar"]) elif float(balance_dict[value]["dollar"]) * 1.03 < float( balance_dict[value]["amount"]): self.sell(value, amount=balance_dict[value]["amount"], dollar=balance_dict[value]["dollar"], price=balance_dict[value]["price"]) else: self.logger.info( f"当前持有{value}合计金额: {balance_dict[value]['amount']}, 对标美元: " f"{balance_dict[value]['dollar']}, 小于阈值不触发交易, " f"买入阈值: {retain_decimals(float(balance_dict[value]['dollar']) / 1.05, 2)}, " f"卖出阈值: {retain_decimals(float(balance_dict[value]['dollar']) * 1.05, 2)}" ) def buy(self, symbol_name, **kwargs): self.trade_lock(symbol_name, self.strategy) try: assert kwargs['dollar'] >= kwargs['amount'] buy_dollar = retain_decimals( (float(kwargs['dollar']) - float(kwargs['amount'])) / 2, 2) if float(buy_dollar) >= TradeLimit.USDT: # 买入 order_id = self.request_client.create_order( symbol_name + 'usdt', AccountType.SPOT, OrderType.BUY_MARKET, buy_dollar, None) self.update_balance_and_dollar(order_id, Action.BUY, symbol_name, buy_dollar=buy_dollar) self.send_mail("触发买入信号", f"动态平衡策略触发买入{buy_dollar}的{symbol_name}") else: self.logger.warning( f"当前欲买入{buy_dollar}美金的{symbol_name}, 不满足最低交易限制") except AssertionError: self.logger.error( f"AssertionError, symbol={symbol_name}, amount={kwargs['amount']}, " f"dollar={kwargs['dollar']}") finally: self.trade_unlock(symbol_name, self.strategy) def sell(self, symbol_name, **kwargs): self.trade_lock(symbol_name, self.strategy) try: assert kwargs['amount'] > kwargs['dollar'] # 获取交易数目精度 precision = self.precision_collection.find_one( {"symbol": symbol_name + "usdt"}, {"amount_precision": 1}) amount_precision = float(precision['amount_precision']) # 计算欲卖出的数目 sell_currency = retain_decimals( (float(kwargs['amount']) - float(kwargs['dollar'])) / 2 / float(kwargs['price']), amount_precision) if float(sell_currency) > TradeLimit.BTC: order_id = self.request_client.create_order( symbol_name + 'usdt', AccountType.SPOT, OrderType.SELL_MARKET, sell_currency, None) self.update_balance_and_dollar(order_id, Action.SELL, symbol_name) self.send_mail("触发卖出信号", f"动态平衡策略触发卖出{sell_currency}的{symbol_name}") else: self.logger.warning( f"当前欲卖出{sell_currency}美金的{symbol_name}, 不满足最低交易限制") except AssertionError: self.logger.error( f"AssertionError, symbol={symbol_name}, amount={kwargs['amount']}, " f"dollar={kwargs['dollar']}") finally: self.trade_unlock(symbol_name, self.strategy) def update_balance_and_dollar(self, order_id, action, symbol_name, **kwargs): order_detail = self.request_client.get_order("symbol", order_id) # 验证订单是否执行完成 while not order_detail.state == OrderState.FILLED: time.sleep(1) self.logger.info(f"{order_id}还未执行完成, 休眠1秒等待执行完成") order_detail = self.request_client.get_order("symbol", order_id) # mongodb中减去已使用的美金 result = self.keep_balance_collection.find_one({"symbol": symbol_name}) dollar = float(result['amount']) if action == 'BUY': dollar -= float(kwargs['buy_dollar']) # mongodb中加上卖出获得的美金 elif action == 'SELL': dollar += float(order_detail.filled_cash_amount) # 格式化美金数 dollar = retain_decimals(dollar, 2) # mongodb更新操作 self.keep_balance_collection.update_one({"symbol": symbol_name}, {"$set": { "amount": dollar }}) self.logger.info(f"{symbol_name}美金数置为: {dollar}") def get_account_balance(self): """ 获取余额大于0的交易对 :return: """ balances = self.request_client.get_account_balance() balance_dict = {} for key, value in enumerate(balances[0].balances): if value.balance > 0 and value.currency != 'usdt': if not self.check_trade_lock_exist(value.currency, self.strategy): price, amount = self.get_account_amount( value.currency, value.balance) if float(amount) >= 1: dollar = self.get_mongodb_dollar( value.currency, amount) balance_dict[value.currency] = { "balance": str(value.balance), "price": str(price), "amount": str(amount), "dollar": dollar } self.logger.debug(balance_dict) return balance_dict def get_account_amount(self, symbol_name, symbol_balance): price = self.get_price(symbol_name + "usdt") amount = str(float(symbol_balance) * float(price)) amount = retain_decimals(amount, 2) return price, amount def get_mongodb_dollar(self, symbol_name, symbol_amount): result = self.keep_balance_collection.find_one({"symbol": symbol_name}) if result is None: self.keep_balance_collection.insert_one({ "symbol": symbol_name, "amount": str(symbol_amount) }) return symbol_amount else: return result['amount'] def get_price(self, symbol_name): """ 获取当前交易对价格 :param symbol_name: :return: """ current_prices = self.request_client.get_latest_candlestick( symbol=symbol_name, interval=CandlestickInterval.DAY1, size=1) return current_prices[0].close
class Trader(): def __init__(self, logger): self.logger = logger self.api = RequestClient(url="https://api-aws.huobi.pro", api_key=g_api_key, secret_key=g_secret_key) self.buy_price = 7314 self.profit = 100 self.avg_price = 0 self.open_price = 0 self.ask = 0 self.bid = 0 self.second_max = 0 self.second_min = 0 self.max = 0 self.min = 0 def trade(self): self.init_candles() result = self.desicion() self.do_trade(result) def get_current_price(self, symbol="btcusdt"): return self.api.get_best_quote(symbol) def update_second(self, high, low): if high > self.max: self.second_max = self.max self.max = high if low < self.min: self.second_min = self.min self.min = low def init_candles(self): candles = self.api.get_candlestick("btcusdt", CandlestickInterval.MIN60, 7) for candle in candles: high = candle.high low = candle.low if self.max == 0: self.max = high self.min = low self.update_second(high, low) def desicion(self, symbol="btcusdt"): current = self.get_current_price(symbol) self.ask = current.ask_price #卖1 self.bid = current.bid_price #买1 self.logger.info("买1:" + str(self.bid)) self.logger.info("卖1:" + str(self.ask)) self.update_second(self.bid, self.ask) print(self.second_max) print(self.second_min) if self.ask >= self.second_max and self.ask - self.buy_price > self.profit: return TradeOpt.Sell elif self.bid <= self.second_min: return TradeOpt.Buy return TradeOpt.Hold def do_trade(self, opt, symbol="btcusdt"): if opt == TradeOpt.Hold: return if opt == TradeOpt.Sell: position = self.get_position(symbol) if position <= 0.01: return order = self.api.create_order(symbol=symbol, account_type=AccountType.SPOT, order_type=OrderType.SELL_LIMIT, amount=position, price=self.ask) # cancel if failed else: # get cash cash = self.get_cash() amount = cash / self.bid order = self.api.create_order(symbol=symbol, account_type=AccountType.SPOT, order_type=OrderType.BUY_LIMIT, amount=amount, price=self.bid) self.buy_price = self.bid def get_position(self, symbol="btcusdt"): account_balance_list = self.api.get_account_balance() if account_balance_list and len(account_balance_list): for account in account_balance_list: if account.account_type == "spot" or account.account_type == "SPOT": if account.balances and len(account.balances): for balance in account.balances: if balance.balance > 0.0 and balance.currency == symbol: print("\tBalance Currency", balance.currency) print("\tBalance Type", balance.balance_type) print("\tBalance", balance.balance) return balance.balance return 0 def get_cash(self): return self.get_position("usdt")
import logging from huobi import SubscriptionClient, RequestClient from huobi.constant.test import * from huobi.model import * from huobi.base.printobject import PrintMix, PrintBasic logger = logging.getLogger("huobi-client") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) def callback(order_req_obj: 'OrderListRequest'): print("---- order list: ----") order_req_obj.print_object() print() request_client = RequestClient(api_key=g_api_key, secret_key=g_secret_key, url = "https://api.huobi.vn") sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key, uri = "https://api.huobi.vn") data = request_client.get_account_balance() if len(data): for account in data: print("============= account info =============") PrintBasic.print_basic(account.id, "Account ID") sub_client.request_order_list_event(symbol="nodeusdt", account_id=account.id, callback=callback, order_states = OrderState.FILLED, client_req_id = None, auto_close = True) break # for frequence limit
class KeepBalanceStrategySocket(BaseStrategy, FileReadAndWrite): """ 动态平衡策略 """ def __init__(self): BaseStrategy.__init__(self) FileReadAndWrite.__init__(self) self.request_client = RequestClient(api_key=self.get_config_value("huobi", "api_key"), secret_key=self.get_config_value("huobi", "secret_key")) self.strategy = 'KeepBalance' self.timeout = float(self.get_config_value("strategy", "timeout")) def signal(self): balance_dict = self.get_account_balance() for key, value in enumerate(balance_dict): if float(balance_dict[value]["amount"]) * 1.03 < float(balance_dict[value]["dollar"]): self.buy(value, amount=balance_dict[value]["amount"], dollar=balance_dict[value]["dollar"]) elif float(balance_dict[value]["dollar"]) * 1.03 < float(balance_dict[value]["amount"]): self.sell(value, amount=balance_dict[value]["amount"], dollar=balance_dict[value]["dollar"], price=balance_dict[value]["price"]) else: self.logger.info(f"当前{value}价格为{balance_dict[value]['price']}, 持有{value}合计金额: " f"{balance_dict[value]['amount']}, 对标美元: {balance_dict[value]['dollar']}, " f"小于阈值不触发交易, " f"买入阈值: {retain_decimals(str(float(balance_dict[value]['dollar']) / 1.03), '2')}, " f"卖出阈值: {retain_decimals(str(float(balance_dict[value]['dollar']) * 1.03), '2')}") def buy(self, symbol_name, **kwargs): self.trade_lock(symbol_name, self.strategy) try: assert kwargs['dollar'] >= kwargs['amount'] buy_dollar = retain_decimals(str((float(kwargs['dollar']) - float(kwargs['amount'])) / 2), '2') if float(buy_dollar) >= TradeLimit.trade_limit_dict['usdt']: # 买入 order_id = self.request_client.create_order(symbol_name + 'usdt', AccountType.SPOT, OrderType.BUY_MARKET, buy_dollar, None) self.update_balance_and_dollar(order_id, Action.BUY, symbol_name, buy_dollar=buy_dollar) # self.send_mail("触发买入信号", f"动态平衡策略触发买入{buy_dollar}的{symbol_name}") WeChatRobot.send_message(f"动态平衡策略触发买入{buy_dollar}的{symbol_name}") else: self.logger.warning(f"当前欲买入{buy_dollar}美金的{symbol_name}, 不满足最低交易限制") except AssertionError: self.logger.error(f"AssertionError, symbol={symbol_name}, amount={kwargs['amount']}, " f"dollar={kwargs['dollar']}") except Exception as E: self.logger.error(E) finally: self.trade_unlock(symbol_name, self.strategy) def sell(self, symbol_name, **kwargs): self.trade_lock(symbol_name, self.strategy) try: assert kwargs['amount'] > kwargs['dollar'] # 获取交易数目精度 precision = self.precision_collection.find_one({"symbol": symbol_name + "usdt"}, {"amount_precision": 1}) amount_precision = float(precision['amount_precision']) # 计算欲卖出的数目 sell_currency = retain_decimals( str((float(kwargs['amount']) - float(kwargs['dollar'])) / 2 / float(kwargs['price'])), str(amount_precision)) if float(sell_currency) > TradeLimit.trade_limit_dict[symbol_name]: order_id = self.request_client.create_order(symbol_name + 'usdt', AccountType.SPOT, OrderType.SELL_MARKET, sell_currency, None) self.update_balance_and_dollar(order_id, Action.SELL, symbol_name) # self.send_mail("触发卖出信号", f"动态平衡策略触发卖出{sell_currency}的{symbol_name}") WeChatRobot.send_message(f"动态平衡策略触发卖出{sell_currency}的{symbol_name}") else: self.logger.warning(f"当前欲卖出{sell_currency}美金的{symbol_name}, 不满足最低交易限制") except AssertionError: self.logger.error(f"AssertionError, symbol={symbol_name}, amount={kwargs['amount']}, " f"dollar={kwargs['dollar']}") except Exception as E: self.logger.error(E) finally: self.trade_unlock(symbol_name, self.strategy) def update_balance_and_dollar(self, order_id, action, symbol_name, **kwargs): order_detail = self.request_client.get_order("symbol", order_id) # 验证订单是否执行完成 while not order_detail.state == OrderState.FILLED: time.sleep(1) self.logger.info(f"{order_id}还未执行完成, 休眠1秒等待执行完成") order_detail = self.request_client.get_order("symbol", order_id) # mongodb中减去已使用的美金 result = self.keep_balance_collection.find_one({"symbol": symbol_name}) dollar = float(result['amount']) if action == 'BUY': dollar -= float(kwargs['buy_dollar']) # mongodb中加上卖出获得的美金 elif action == 'SELL': dollar += float(order_detail.filled_cash_amount) # 格式化美金数 dollar = retain_decimals(str(dollar), '2') # mongodb更新操作 self.keep_balance_collection.update_one({"symbol": symbol_name}, {"$set": {"amount": dollar}}) self.logger.info(f"{symbol_name}美金数置为: {dollar}") def get_account_balance(self): """ 获取余额大于0的交易对 :return: """ balances = self.request_client.get_account_balance() balance_dict = {} for key, value in enumerate(balances[0].balances): if value.balance > 0 and value.currency != 'usdt': price, amount = self.get_account_amount(value.currency, value.balance) if float(amount) >= 1: if not self.check_trade_lock_exist(value.currency, self.strategy): dollar = self.get_mongodb_dollar(value.currency, amount) balance_dict[value.currency] = {"balance": str(value.balance), "price": str(price), "amount": str(amount), "dollar": dollar} self.logger.debug(balance_dict) return balance_dict def get_account_amount(self, symbol_name, symbol_balance): price = self.get_price(symbol_name + "usdt") amount: str = str(float(symbol_balance) * float(price)) amount: str = retain_decimals(str(amount), '2') return price, amount def get_mongodb_dollar(self, symbol_name, symbol_amount): result = self.keep_balance_collection.find_one({"symbol": symbol_name}) if result is None: self.keep_balance_collection.insert_one({"symbol": symbol_name, "amount": str(symbol_amount)}) return symbol_amount else: return result['amount'] def get_price(self, symbol_name: str) -> str: """ 获取当前交易对价格 :param symbol_name: :return: """ try: file = FileReadAndWrite.read(f"{self.get_config_value('strategy', 'price_file_locate')}{symbol_name}.txt") time_stamp, price = file.split(",") # time.time()获取的时间为0时区时间, 火币为东8区时间, 因此减去28800秒 current_time = time.time() - 28800 if abs(current_time - float(time_stamp) / 1000) < self.timeout: return price else: self.logger.error("动态平衡策略获取时间戳出错, 价格超时") os.system("/root/miniconda3/bin/supervisorctl -u gator -p zhangpei529\!\@ -c " "/usr/supervisor/supervisord.conf restart collect_price_data") self.logger.info("重启价格获取程序") raise TimeoutError except FileNotFoundError: self.logger.error(f"{self.get_config_value('strategy', 'price_file_locate')}{symbol_name}.txt文件不存在") raise FileNotFoundError