def make_order(symbol=CoinSymbol.Btcusdt, sell=True, amount=0): try: request_client = RequestClient(api_key=g_api_key, secret_key=g_secret_key) if not test_flag: if sell: order_id = request_client.create_order(symbol.symbol, AccountType.MARGIN, OrderType.SELL_MARKET, amount, price=0) else: order_id = request_client.create_order(symbol.symbol, AccountType.MARGIN, OrderType.BUY_MARKET, amount, price=0) else: print("test mode on") order_info.order_id = order_id except Exception as e: print(e) print("retrying in 1s") time.sleep(1) return make_order()
from huobi import RequestClient from huobi.constant.test import * from huobi.model import * request_client = RequestClient(api_key=g_api_key, secret_key=g_secret_key) symbol_test = "eosusdt" order_id = request_client.create_order(symbol_test, AccountType.SPOT, OrderType.BUY_LIMIT, amount=1, price=1.011) print(order_id) request_client.cancel_order(symbol_test, order_id) symbol_test = "xrpusdt" order_id = request_client.create_order(symbol_test, AccountType.MARGIN, OrderType.BUY_LIMIT, amount=101, price=0.01) print(order_id) request_client.cancel_order(symbol_test, order_id) symbol_test = "xrpusdt" order_id = request_client.create_order(symbol_test, AccountType.SUPER_MARGIN, OrderType.BUY_LIMIT, amount=101, price=0.011) print(order_id)
class Trader(): def __init__(self, logger, wechat): 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.init_balance = 1.257 self.update_interval = 6 * 60 self.avg_price = 0 self.open_price = 0 self.ask = 0 self.bid = 0 self.second_max = 0 self.second_min = 0 self.second_max_t = datetime.datetime.now() self.second_min_t = datetime.datetime.now() self.wechat = wechat self.orders = queue.Queue() self.status_thread = StatusThread(self.api, self.init_balance, self.orders, logger, wechat) self.status_thread.start() def get_float(self, f_str, n): f_str = str(f_str) a, b, c = f_str.partition('.') c = (c + "0" * n)[:n] tmp = ".".join([a, c]) return float(tmp) def trade(self): self.update_candles() time.sleep(6) result = self.desicion() self.do_trade(result) def get_current_price(self, symbol="btcusdt"): return self.api.get_best_quote(symbol) def update_candles(self): ct = datetime.datetime.now() if self.ask > 0 and (ct - self.second_max_t).seconds < self.update_interval and (ct - self.second_min_t).seconds < self.update_interval: return candles = self.api.get_candlestick("btcusdt", CandlestickInterval.MIN60, 7) highs = [candle.high for candle in candles] lows = [candle.low for candle in candles] highs.sort() lows.sort() self.second_max = highs[-2] self.second_min = lows[1] self.logger.info("【更新】second_max:" + str(self.second_max)) self.logger.info("【更新】second_min:" + str(self.second_min)) 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)) 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.api.get_position() position = self.get_float(position, 2) self.wechat.send_message("【决策】:卖出\n") if position <= 0.01: self.wechat.send_message("仓位不足:" + str(position)) return order = self.api.create_order(symbol=symbol, account_type=AccountType.SPOT, order_type=OrderType.SELL_LIMIT, amount=position, price=self.ask) message = "【新建订单】\n 方向:卖出\n 数量:{0}\n 价格:{1}".format(position, self.ask) self.wechat.send_message(message) self.orders.put(order) else: self.wechat.send_message("【决策】:买入\n") cash = self.api.get_cash() if cash < 20: self.wechat.send_message("现金不足:" + str(cash)) return amount = cash / self.bid amount = self.get_float(amount, 2) 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 message = "【新建订单】\n 方向:买入\n 数量:{0}\n 价格:{1}".format(amount, self.bid) self.wechat.send_message(message) self.orders.put(order)
from huobi import RequestClient from huobi.constant.test import * from huobi.model import * request_client = RequestClient(api_key=g_api_key, secret_key=g_secret_key) symbol_test = "btcusdt" order_id = request_client.create_order(symbol_test, AccountType.MARGIN, OrderType.BUY_LIMIT, amount=0.001, price=8800) print(order_id) request_client.cancel_order(symbol_test, order_id)
class OrderRouter(object): def __init__(self, apikey, secretkey, password): self._api = RequestClient(api_key=apikey, secret_key=secretkey) self.account_type = AccountType.SPOT def _format_instrument_id(self, instrument_id): return instrument_id.lower().replace('-', '') def _decode_type(self, order_type): if not order_type: return None, None tmp = order_type.split('-') side = tmp[0] o_type = tmp[1] if side not in ['buy', 'sell']: side = None if o_type not in ['limit', 'market', 'ioc']: o_type = None return side, o_type def _decode_state(self, state): if state == 'submitted': return 'open' return state def _timestamp_to_datetime(self, timestamp): return datetime.datetime.fromtimestamp((timestamp + 28800000) / 1000) def _format_order(self, instrument_id, order_info): def fill_obj(o): side, o_type = self._decode_type(o.order_type) return { 'instrument_id': instrument_id, 'order_id': str(o.order_id), 'client_oid': '', 'price': o.price, 'size': o.amount, 'timestamp': o.created_timestamp, 'finished_timestamp': o.finished_timestamp, 'finished_datetime': self._timestamp_to_datetime(o.finished_timestamp), 'canceled_timestamp': o.canceled_timestamp, 'datetime': self._timestamp_to_datetime(o.created_timestamp), 'filled_size': o.filled_amount, 'filled_notional': o.filled_cash_amount, 'side': side, 'type': o_type, 'state': o.state, 'status': self._decode_state(o.state), 'created_at': datetime.datetime.now(), 'updated_at': datetime.datetime.now() } if isinstance(order_info, list): ret = [] for o in order_info: ret.append(fill_obj(o)) else: ret = fill_obj(order_info) return ret def check_position(self, symbol): psss def submit_spot_order(self, client_oid, type, side, instrument_id, price, size, notional, order_type='0', timeout=20, wait_flag=False): instrument_id = self._format_instrument_id(instrument_id) order_type = '{}-{}'.format(param['side'], param['type']) order_id = self._api.create_order(instrument_id, self.account_type, order_type, size, price) return {'order_id': order_id} # take orders # 市价单 # params = [ # {"client_oid":"20180728","instrument_id":"btc-usdt","side":"sell","type":"market"," size ":"0.001"," notional ":"10001","margin_trading ":"1"}, # {"client_oid":"20180728","instrument_id":"btc-usdt","side":"sell","type":"limit"," size ":"0.001","notional":"10002","margin_trading ":"1"} # ] # 限价单 # params = [ # {"client_oid":"20180728","instrument_id":"btc-usdt","side":"sell","type":"limit","size":"0.001","price":"10001","margin_trading ":"1"}, # {"client_oid":"20180728","instrument_id":"btc-usdt","side":"sell","type":"limit","size":"0.001","price":"10002","margin_trading ":"1"} # ] def submit_orders(self, params): ret = [] for param in params: instrument_id = self._format_instrument_id(param['instrument_id']) order_type = '{}-{}'.format(param['side'], param['type']) try: order_id = self._api.create_order(instrument_id, self.account_type, order_type, param['size'], param['price']) order_id = str(order_id) print('submit order id: {}, order_type: {}, price: {}'.format( order_id, order_type, param['price'])) ret.append({ 'order_id': order_id, 'side': param['side'], 'price': param['price'] }) except Exception as e: print('submit_orders err: {}'.format(e)) print('account type:{}, order_type:{}, size:{}, price:{}'.format(self.account_type, order_type, param['size'], param['price'])) time.sleep(0.01) return ret def get_order_info(self, order_id, instrument_id, client_oid=''): order_info = self._api.get_order( self._format_instrument_id(instrument_id), order_id) return self._format_order(instrument_id, order_info) def cancel_order(self, order_id, instrument_id): return self._api.cancel_order( self._format_instrument_id(instrument_id), order_id) # revoke orders # params example: # [ # {"instrument_id":"btc-usdt","order_ids":[1600593327162368,1600593327162369]}, # {"instrument_id":"ltc-usdt","order_ids":[243464,234465]} # ] def cancel_orders(self, params): ret = [] for param in params: instrument_id = self._format_instrument_id(param['instrument_id']) ret.append( self._api.cancel_orders(instrument_id, param['order_ids'])) time.sleep(0.01) return ret def get_orders_pending(self, instrument_id): ret = [] open_orders = self._api.get_open_orders( self._format_instrument_id(instrument_id), self.account_type, size=100) return self._format_order(instrument_id, open_orders) def get_kline(self, instrument_id, start, end, granularity): pass def get_ticker(self, instrument_id): last_trade = self._api.get_last_trade( self._format_instrument_id(instrument_id)) return {'last': last_trade.price} def get_coin_info(self, instrument_id='all'): # TODO 把sdk方法get_exchange_info的symobl和currency分离出来 exchange_info = self._api.get_exchange_info() symbol_list = exchange_info.symbol_list for sl in symbol_list: if sl.symbol == self._format_instrument_id(instrument_id): return { 'instrument_id': instrument_id, 'base_currency': sl.base_currency, 'quote_currency': sl.quote_currency, 'tick_size': sl.price_precision, 'size_increment': sl.amount_precision } return None def get_account_info(self): account_balances = self._api.get_account_balance_by_account_type( self.account_type) details_obj = {} for b in account_balances.balances: if b.balance: if b.currency not in details_obj: if b.balance_type == BalanceType.TRADE: details_obj[b.currency] = { 'currency': b.currency.upper(), 'frozen': 0, 'balance': b.balance, 'available': b.balance } elif b.balance_type == BalanceType.FROZEN: details_obj[b.currency] = { 'currency': b.currency.upper(), 'frozen': b.balance, 'balance': b.balance, 'available': 0 } else: if b.balance_type == BalanceType.TRADE: details_obj[b.currency]['available'] += b.balance details_obj[b.currency]['balance'] += b.balance elif b.balance_type == BalanceType.FROZEN: details_obj[b.currency]['frozen'] += b.balance details_obj[b.currency]['balance'] += b.balance return list(details_obj.values()) def get_coin_account_info(self, symbol): balances = self._api.get_account_balance_by_account_type( self.account_type) ret = {'currency': symbol, 'frozen': 0, 'balance': 0, 'available': 0} for b in balances.get_balance(symbol.lower()): if b.balance_type == BalanceType.TRADE: ret['balance'] += b.balance ret['available'] = b.balance elif b.balance_type == BalanceType.FROZEN: ret['balance'] += b.balance ret['frozen'] = b.balance return ret def get_coin_balance(self, symbol): return self.get_coin_account_info(symbol)['balance'] def get_coin_available(self, symbol): return self.get_coin_account_info(symbol)['available'] def get_oneday_orders(self, instrument_id, stime, state): if stime > datetime.datetime.now(): return [] start_date = stime.strftime('%Y-%m-%d') end_date = start_date # (stime + datetime.timedelta(days=1)).strftime('%Y-%m-%d') orders = [] start_id = None size = 100 format_instrument_id = self._format_instrument_id(instrument_id) while True: order = self._api.get_historical_orders( format_instrument_id, state, start_date=start_date, end_date=end_date, start_id=start_id, size=size) #print('Fetched orders, date: {}, pair: {}, total: {}'.format(start_date, instrument_id, len(order))) format_orders = self._format_order(instrument_id, order) orders += format_orders # print('Fetched orders, pair: %s, total: %d', instrument_id, len(format_orders)) if len(format_orders) < size: break else: start_id = min([o['order_id'] for o in format_orders]) time.sleep(0.5) return orders def get_orders(self, instrument_id, stime, etime, state): date_list = pd.date_range( stime.replace(hour=0, minute=0, second=0, microsecond=0), etime.replace(hour=0, minute=0, second=0, microsecond=0)) orders = [] for d in date_list: orders += self.get_oneday_orders(instrument_id, d, state) return [ o for o in orders if o['datetime'] >= stime and o['datetime'] < etime ]
from huobi import RequestClient from huobi.model import * from huobi.base.printobject import PrintMix symbol_test = "eosht" client_order_id_test = "xxxxxx" # unique id in 24hours request_client = RequestClient(api_key="xxxxxx", secret_key="xxxxxx") order_id = request_client.create_order(symbol=symbol_test, account_type=AccountType.SPOT, order_type=OrderType.SELL_LIMIT, amount=1.0, price=20.12, client_order_id=client_order_id_test, stop_price=12, operator="gte") print("create new order id : " + (str(order_id)) + " with client id " + client_order_id_test) print("\n\n") orderObj = request_client.get_order(symbol=symbol_test, order_id=order_id) print("get order by order id : " + (str(order_id))) PrintMix.print_data(orderObj) print("\n\n") orderObj = request_client.get_order_by_client_order_id( client_order_id=client_order_id_test) print("get order by client order id : " + client_order_id_test) PrintMix.print_data(orderObj) print("\n\n")
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
from huobi import RequestClient from huobi.constant.test import * from huobi.model import * request_client = RequestClient(api_key=g_api_key, secret_key=g_secret_key) client_order_id_tmp = "1990063" symbol_test = "btcusdt" order_id = request_client.create_order(symbol_test, AccountType.SPOT, OrderType.BUY_LIMIT, amount=5, price=1.01, client_order_id=client_order_id_tmp) print(order_id) print("\n============== get open order ===============\n") order_obj = request_client.get_order(symbol=symbol_test, order_id=order_id) order_obj.print_object() request_client.cancel_order(symbol_test, order_id) print("\n============== get cancel order ===============\n") order_obj = request_client.get_order(symbol=symbol_test, order_id=order_id) order_obj.print_object()
class Td(): def __init__(self, logger, wechat): 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 = 300 self.init_balance = 1.257 self.update_interval = 6 * 60 self.avg_price = 0 self.open_price = 0 self.ask = 0 self.bid = 0 self.wechat = wechat self.lastTd = None self.resetCountdownOnTDST = True self.resetSetupCounterAfterCountdownHit13 = True self.result = list() self.orders = queue.Queue() self.status_thread = StatusThread(self.api, self.init_balance, self.orders, logger, wechat) self.status_thread.start() def get_float(self, f_str, n): f_str = str(f_str) a, b, c = f_str.partition('.') c = (c + "0" * n)[:n] tmp = ".".join([a, c]) return float(tmp) def trade(self): self.update_candles() time.sleep(300) opt = self.desicion() #self.do_trade(opt) def get_current_price(self, symbol="btcusdt"): return self.api.get_best_quote(symbol) def update_candles(self): candles = self.api.get_candlestick("btcusdt", CandlestickInterval.HOUR4, 200) self.calc_td(candles) self.logger.info("td buy seq:==>") i = 0 for item in self.result[-24:]: self.logger.info(str(i) +":" + str(item.buySetupIndex)) #self.logger.info(str(i) +":" + str(item.buyCoundownIndex)) #self.logger.info(str(i) +":" + str(item.buySetup)) #self.logger.info(str(i) +":" + str(item.buySetupPerfection)) i += 1 self.logger.info("td sell seq:==>") i = 0 for item in self.result[-24:]: self.logger.info(str(i) + ":" + str(item.sellSetupIndex)) #self.logger.info(str(i) + ":" + str(item.sellCoundownIndex)) #self.logger.info(str(i) + ":" + str(item.sellSetup)) #self.logger.info(str(i) + ":" + str(item.sellSetupPerfection)) i += 1 def desicion(self, symbol="btcusdt"): current = self.get_current_price(symbol) self.ask = current.ask_price #卖1 self.bid = current.bid_price #买1 last_second = self.result[-2] self.lastTd = self.result[-1] td_buy = (last_second.buySetup == False and last_second.buySetupPerfection == False) \ and (self.lastTd.buySetupPerfection and self.lastTd.buySetup and (self.lastTd.buySetupIndex == 9 or self.lastTd.buySetupIndex == 13)) td_sell = (last_second.sellSetup == False and last_second.sellSetupPerfection == False) \ and (self.lastTd.sellSetupPerfection and self.lastTd.sellSetup and (self.lastTd.sellSetupIndex == 9 or self.lastTd.sellSetupIndex == 13)) self.logger.info("买1:" + str(self.bid)) self.logger.info("卖1:" + str(self.ask)) self.logger.info("td_buy:" + str(td_buy)) self.logger.info("td_sell:" + str(td_sell)) if td_sell and self.ask - self.buy_price > self.profit: return TradeOpt.Sell elif td_buy: return TradeOpt.Buy return TradeOpt.Hold def do_trade(self, opt, symbol="btcusdt"): if opt == TradeOpt.Hold: return if opt == TradeOpt.Sell: position = self.api.get_position() position = self.get_float(position, 2) msg = "【状态】卖出TD序列值达标:{0}\n 是否达到最优:{1}\n 【决策】:卖出\n".format(self.lastTd.sellSetup, self.lastTd.sellSetupPerfection) self.wechat.send_message(msg) if position <= 0.01: self.wechat.send_message("仓位不足:" + str(position)) return order = self.api.create_order(symbol=symbol, account_type=AccountType.SPOT, order_type=OrderType.SELL_LIMIT, amount=position, price=self.ask) message = "【新建订单】\n 方向:卖出\n 数量:{0}\n 价格:{1}".format(position, self.ask) self.wechat.send_message(message) self.orders.put(order) else: msg = "【状态】买入TD序列值达标:{0}\n 是否达到最优:{1}\n 【决策】:买入\n".format(self.lastTd.buySetup, self.lastTd.buySetupPerfection) self.wechat.send_message(msg) cash = self.api.get_cash() if cash < 20: self.wechat.send_message("现金不足:" + str(cash)) return amount = cash / self.bid amount = self.get_float(amount, 2) 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 message = "【新建订单】\n 方向:买入\n 数量:{0}\n 价格:{1}".format(amount, self.bid) self.wechat.send_message(message) self.orders.put(order) def calc_td(self, ohlc): i = 0 ohlc.reverse() for item in ohlc: self.logger.info(ohlc[i].close) resultObj = ResultObj() if i >= 5: resultObj.sellCoundownIndex = self.result[i - 1].sellCoundownIndex resultObj.buyCoundownIndex = self.result[i - 1].buyCoundownIndex resultObj.sellSetup = self.result[i - 1].sellSetup resultObj.buySetup = self.result[i - 1].buySetup resultObj.TDSTBuy = self.result[i - 1].TDSTBuy resultObj.TDSTSell = self.result[i - 1].TDSTSell resultObj.sellSetupPerfection = self.result[i - 1].sellSetupPerfection resultObj.buySetupPerfection = self.result[i - 1].buySetupPerfection closeLessThanCloseOf4BarsEarlier = ohlc[i].close < ohlc[i - 4].close closeGreaterThanCloseOf4BarsEarlier = ohlc[i].close > ohlc[i - 4].close resultObj.bearishFlip = ohlc[i - 1].close > ohlc[i - 5].close and closeLessThanCloseOf4BarsEarlier resultObj.bullishFlip = ohlc[i - 1].close < ohlc[i - 5].close and closeGreaterThanCloseOf4BarsEarlier if (resultObj.bearishFlip or (self.result[i - 1].buySetupIndex > 0 and closeLessThanCloseOf4BarsEarlier)): resultObj.buySetupIndex = (self.result[i - 1].buySetupIndex + 1 - 1) % 9 + 1 resultObj.TDSTBuy = max(item.high, self.result[i - 1].TDSTBuy) elif (resultObj.bullishFlip or (self.result[i - 1].sellSetupIndex > 0 and closeGreaterThanCloseOf4BarsEarlier)): resultObj.sellSetupIndex = (self.result[i - 1].sellSetupIndex + 1 - 1) % 9 + 1 resultObj.TDSTSell = min(item.low, self.result[i - 1].TDSTSell) if (resultObj.buySetupIndex == 9): resultObj.buySetup = True resultObj.sellSetup = False resultObj.sellSetupPerfection = False resultObj.buySetupPerfection = (ohlc[i - 1].low < ohlc[i - 3].low and ohlc[i - 1].low < ohlc[i - 2].low) or ( ohlc[i].low < ohlc[i - 3].low and ohlc[i].low < ohlc[i - 2].low) if (resultObj.sellSetupIndex == 9): resultObj.sellSetup = True resultObj.buySetup = False resultObj.buySetupPerfection = False resultObj.sellSetupPerfection = (ohlc[i - 1].high > ohlc[i - 3].high and ohlc[i - 1].high > ohlc[i - 2].high) or ( ohlc[i].high > ohlc[i - 3].high and ohlc[i].high > ohlc[i - 2].high) self.calculateTDBuyCountdown(self.result, resultObj, ohlc, item, i) self.calculateTDSellCountdown(self.result, resultObj, ohlc, item, i) self.result.append(resultObj) i += 1 def calculateTDSellCountdown(self, result, resultObj, ohlc, item, i): if (result[i - 1].sellSetup and resultObj.buySetup) or (self.resetCountdownOnTDST and item.close < result[i - 1].TDSTSell): resultObj.sellCoundownIndex = 0 resultObj.countdownResetForTDST = True elif resultObj.sellSetup: if item.close > ohlc[i - 2].high: resultObj.sellCoundownIndex = (result[i - 1].sellCoundownIndex + 1 - 1) % 13 + 1 resultObj.countdownIndexIsEqualToPreviousElement = False if (resultObj.sellCoundownIndex == 13 and result[i - 1].sellCoundownIndex == 13): resultObj.sellCoundownIndex = 0 if (self.resetSetupCounterAfterCountdownHit13 and (resultObj.sellCoundownIndex == 13 and resultObj.sellSetupIndex > 0)): resultObj.sellSetupIndex = 1 if (resultObj.sellCoundownIndex != 13 and result[i - 1].sellCoundownIndex == 13): resultObj.sellSetup = False resultObj.sellSetupPerfection = False resultObj.sellCoundownIndex = 0 def calculateTDBuyCountdown(self, result, resultObj, ohlc, item, i): if (result[i - 1].buySetup and resultObj.sellSetup) or (self.resetCountdownOnTDST and item.close > result[i - 1].TDSTBuy): resultObj.buyCoundownIndex = 0 resultObj.countdownResetForTDST = True elif resultObj.buySetup: if item.close < ohlc[i - 2].low: resultObj.buyCoundownIndex = (result[i - 1].buyCoundownIndex + 1 - 1) % 13 + 1 resultObj.countdownIndexIsEqualToPreviousElement = False if (resultObj.buyCoundownIndex == 13 and result[i - 1].buyCoundownIndex == 13): resultObj.buyCoundownIndex = 0 if (self.resetSetupCounterAfterCountdownHit13 and (resultObj.buyCoundownIndex == 13 and resultObj.buySetupIndex > 0)): resultObj.buySetupIndex = 1 if (resultObj.buyCoundownIndex != 13 and result[i - 1].buyCoundownIndex ==13): resultObj.buySetup = False resultObj.buySetupPerfection = False resultObj.buyCoundownIndex = 0
class QsHuobi(object): """ qsq系统提供的火币接口,可通过此接口获取数据和交易等 要想进行交易,必须在qs/config/config.ini中设置好自己的火币api密钥 """ def __init__(self): [self.api_key, self.secret_key, self.client_order_id] = self.get_apikey() self.request_client = RequestClient(api_key=self.api_key, secret_key=self.secret_key) #self.subscription_client = SubscriptionClient() def get_apikey(self): cfg = ConfigParser() cfg.read(QsEnv.g_project_config) return [ cfg.get('huobi', 'huobiapi_key'), cfg.get('huobi', 'huobisecret_key'), cfg.get('huobi', 'client_order_id') ] def get_24h_trade_statistics(self, pair="btcusdt"): """ param: pair 想要获取的交易对,默认为btcusdt 获取24小时的市场数据,返回结构体成员包括有 timestamp, high, low, open, close, volume 可使用trade_statistics.high这样的方式获取对应数据 """ trade_statistics = self.request_client.get_24h_trade_statistics(pair) return trade_statistics def get_latest_candlestick(self, pair="btcusdt", interval=CandlestickInterval.MIN1, size=10): """ param: pair 想要获取的交易对,默认为btcusdt param: interval 时间间隔,默认为MIN1, 可选有MIN1 MIN5 MIN15 MIN30 MIN60 DAY1 MON1 WEEK1 YEAR1 param: size 获取的数据条数,默认为10,选择范围为[1,2000] 获取最近一段时间的K线数据,返回一个list,这个list的每一项的结构体成员包括有 timestamp, high, low, open, close, volume 可使用member.high这样的方式获取对应数据 """ candlestick_list = self.request_client.get_latest_candlestick( pair, interval, size) return candlestick_list def get_exchange_currencies(self): """ 获取火币所有交易币种 """ return self.request_client.get_exchange_currencies() def get_exchange_info(self): """ 获取交易所信息,返回交易对和支持币种,使用案例 for symbol in exchange_info.symbol_list: print(symbol.symbol) for currency in exchange_info.currencies: print(currency) """ return self.request_client.get_exchange_info() def get_fee_rate(self, symbol="btcusdt"): """ 获取交易手续费,返回一个FeeRate对象,成员包括 symbol 对应币种 maker_fee 卖方手续费 taker_fee 买方手续费 实际使用中,symbol也为一个费率 """ result = self.request_client.get_fee_rate(symbols=symbol) return result[0] def get_historical_orders(self, symbol="ethusdt", order_state=OrderState.CANCELED, order_type=None, start_date=None, end_date=None, start_id=None, size=None): """ param: symbol 符号(必须) param: order_state 订单状态(必须),可选参数有SUBMITTED PARTIAL_FILLED CANCELLING PARTIAL_CANCELED FILLED CANCELED INVALID param: order_type 订单类型(可选),可选参数有SELL_LIMIT BUY_LIMIT BUY_MARKET SELL_MARKET BUY_IOC SELL_IOC BUY_LIMIT_MAKER SELL_LIMIT_MAKER BUY_STOP_LIMIT SELL_STOP_LIMIT INVALID param: start_date 开始日期(可选) 格式为 yyyy-mm-dd param: end_date 结束日期(可选) 格式为 yyyy-mm-dd param: start_id(可选) 订单起始id,暂时忽略 param: size(可选) 大小,暂时忽略 获取历史订单 """ orders = self.request_client.get_historical_orders( symbol=symbol, order_state=order_state, order_type=order_type, start_date=start_date, end_date=end_date, start_id=start_id, size=size) return orders def get_historical_trade(self, symbol="btcusdt", size=5): """ param: symbol 符号(必须) param: size 交易列表的大小(必须) 获取历史交易数据,返回trade_list对象列表,每个对象有如下几个成员 timestamp trade_id price amount direction """ trade_list = self.request_client.get_historical_trade(symbol, size) return trade_list def get_market_trade(self, symbol="btcusdt"): """ param: symbol 符号,默认为btcusdt 获取当前市场上的交易,返回一个trade对象组成的tradelist列表,每个trade对象的成员有 price, amount, trade_id timestamp, direction """ trades = self.request_client.get_market_trade(symbol=symbol) return trades def get_open_orders(self, symbol="htusdt", account_type=AccountType.SPOT, direct="next"): """ 获取自己账户当前开放的交易,返回order数组,每个Order对象有 order_id, symbol, price, amount, account_type, created_timestamp, order_type, filled_amount, filled_cash_amount, filled_fees, source, state """ orders = self.request_client.get_open_orders(symbol=symbol, account_type=account_type, direct=direct) return orders def get_order_recent_48hour(self, symbol=None, start_time=None, end_time=None, size=None, direct=None): """ 获取自己账户48小时内的交易记录,返回order数组 """ orders = self.request_client.get_order_recent_48hour( symbol=symbol, start_time=start_time, end_time=end_time, size=size, direct=direct) return orders def get_price_depth(self, symbol, size): """ 获取当前市场的交易深度,symbol 为交易对,size为头部的几个交易,一个用例如下 i = 0 for entry in depth.bids: i = i + 1 print(str(i) + ": price: " + str(entry.price) + ", amount: " + str(entry.amount)) i = 0 for entry in depth.asks: i = i + 1 print(str(i) + ": price: " + str(entry.price) + ", amount: " + str(entry.amount)) """ depth = self.request_client.get_price_depth(symbol, size) return depth def order(self, symbol="btcusdt", account_type=AccountType.SPOT, order_type=OrderType.SELL_LIMIT, amount=1.0, price=None, stop_price=None, operator=None): """ 下单函数,谨慎使用 必须提供的参数为symbol,account_type,order_type,amount param: account_type 账户类型,包括有SPOT MARGIN OTC POINT param: order_type 订单类型,包括有SELL_LIMIT BUY_LIMIT BUY_MARKET SELL_MARKET BUY_IOC SELL_IOC """ order_id = self.request_client.create_order(symbol, account_type, order_type, amount, price, self.client_order_id, stop_price, operator) return order_id def cancle_order(self, symbol="btcusdt", order_id="00000"): """ 取消某笔订单 """ cancle_state = self.request_client.cancel_order(symbol, order_id) return cancle_state def get_order(self, symbol="btcusdt", order_id="000000"): """ 根据order_id获取某笔交易,每个Order对象有 order_id, symbol, price, amount, account_type, created_timestamp, order_type, filled_amount, filled_cash_amount, filled_fees, source, state """ order = self.request_client.get_order(symbol=symbol, order_id=order_id) return order def get_order_by_client_order_id(self): """ 根据client_order_id来获取订单, 每个Order对象有 order_id, symbol, price, amount, account_type, created_timestamp, order_type, filled_amount, filled_cash_amount, filled_fees, source, state """ order = self.request_client.get_order_by_client_order_id( client_order_id=self.client_order_id) return order def cancel_client_order(self): """ 根据client_order_id取消某笔交易 """ self.request_client.cancel_client_order( client_order_id=self.client_order_id)
from huobi import RequestClient from huobi.constant.test import * from huobi.model import * request_client = RequestClient(api_key=g_api_key, secret_key=g_secret_key) symbol_test = "eosusdt" order_id = request_client.create_order(symbol_test, AccountType.SPOT, OrderType.SELL_LIMIT, amount=1.0, price=100.0) print(order_id) request_client.cancel_order(symbol_test, order_id)
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")
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
from huobi import RequestClient from huobi.model import * request_client = RequestClient(api_key="xxxxxx", secret_key="xxxxxx") order_id = request_client.create_order("btcusdt", AccountType.SPOT, OrderType.BUY_LIMIT, 1.0, 1.0) request_client.cancel_order("btcusdt", order_id)